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 results.reserve(module.getNumPorts());
672 ArrayRef<Attribute> domains =
module.getDomainInfo();
673 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
674 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
675 module.getPortDirection(i), module.getPortSymbolAttr(i),
676 module.getPortLocation(i),
677 AnnotationSet::forPort(module, i),
678 domains.empty() ? Attribute{} : domains[i]});
683SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
685SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
687SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
689SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
692 if (dir == Direction::In)
693 return hw::ModulePort::Direction::Input;
694 if (dir == Direction::Out)
695 return hw::ModulePort::Direction::Output;
696 assert(0 &&
"invalid direction");
701 SmallVector<hw::PortInfo> results;
702 auto aname = StringAttr::get(module.getContext(),
703 hw::HWModuleLike::getPortSymbolAttrName());
704 auto emptyDict = DictionaryAttr::get(module.getContext());
705 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
706 auto sym =
module.getPortSymbolAttr(i);
708 {{
module.getPortNameAttr(i), module.getPortType(i),
709 dirFtoH(module.getPortDirection(i))},
711 sym ? DictionaryAttr::get(
713 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
715 module.getPortLocation(i)});
720SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
721 return ::getPortListImpl(*
this);
724SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
725 return ::getPortListImpl(*
this);
728SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
729 return ::getPortListImpl(*
this);
732SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
733 return ::getPortListImpl(*
this);
737 auto sym =
module.getPortSymbolAttr(idx);
738 auto attrs = sym ? DictionaryAttr::getWithSorted(
740 ArrayRef(mlir::NamedAttribute(
741 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
742 : DictionaryAttr::get(module.getContext());
743 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
744 dirFtoH(module.getPortDirection(idx))},
747 module.getPortLocation(idx)};
751 return ::getPortImpl(*
this, idx);
755 return ::getPortImpl(*
this, idx);
759 return ::getPortImpl(*
this, idx);
763 return ::getPortImpl(*
this, idx);
767BlockArgument FModuleOp::getArgument(
size_t portNumber) {
774 Attribute domainInfoAttr,
775 ArrayRef<unsigned> indexMap) {
777 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
778 if (!di || di.empty())
779 return domainInfoAttr;
782 SmallVector<Attribute> domainInfo;
783 for (
auto attr : di) {
784 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
785 auto newIdx = indexMap[oldIdx];
786 if (oldIdx == newIdx)
787 domainInfo.push_back(attr);
789 domainInfo.push_back(IntegerAttr::get(
790 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
792 return ArrayAttr::get(
context, domainInfo);
799 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
802 unsigned oldNumArgs = op.getNumPorts();
803 unsigned newNumArgs = oldNumArgs + ports.size();
806 SmallVector<unsigned> indexMap(oldNumArgs);
808 for (
size_t i = 0; i < oldNumArgs; ++i) {
809 while (inserted < ports.size() && ports[inserted].first == i)
811 indexMap[i] = i + inserted;
815 auto existingDirections = op.getPortDirectionsAttr();
816 ArrayRef<Attribute> existingNames = op.getPortNames();
817 ArrayRef<Attribute> existingTypes = op.getPortTypes();
818 ArrayRef<Attribute> existingLocs = op.getPortLocations();
819 assert(existingDirections.size() == oldNumArgs);
820 assert(existingNames.size() == oldNumArgs);
821 assert(existingTypes.size() == oldNumArgs);
822 assert(existingLocs.size() == oldNumArgs);
824 SmallVector<bool> newDirections;
825 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
827 newDirections.reserve(newNumArgs);
828 newNames.reserve(newNumArgs);
829 newTypes.reserve(newNumArgs);
830 newDomains.reserve(newNumArgs);
831 newAnnos.reserve(newNumArgs);
832 newSyms.reserve(newNumArgs);
833 newLocs.reserve(newNumArgs);
835 auto emptyArray = ArrayAttr::get(op.getContext(), {});
838 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
839 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
840 newDirections.push_back(existingDirections[oldIdx]);
841 newNames.push_back(existingNames[oldIdx]);
842 newTypes.push_back(existingTypes[oldIdx]);
844 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
845 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
846 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
847 newLocs.push_back(existingLocs[oldIdx]);
852 for (
auto [idx, port] : ports) {
853 migrateOldPorts(idx);
855 newNames.push_back(port.name);
856 newTypes.push_back(TypeAttr::get(port.type));
859 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
861 auto annos = port.annotations.getArrayAttr();
862 newAnnos.push_back(annos ? annos : emptyArray);
863 newSyms.push_back(port.sym);
864 newLocs.push_back(port.loc);
867 migrateOldPorts(oldNumArgs);
871 if (llvm::all_of(newAnnos, [](Attribute attr) {
872 return cast<ArrayAttr>(attr).empty();
878 if (llvm::all_of(newDomains, [](Attribute attr) {
881 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
882 return arrayAttr.empty();
888 op->setAttr(
"portDirections",
890 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
891 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
892 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
893 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
894 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
895 op.setPortSymbols(newSyms);
896 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
907 ArrayAttr domainInfoAttr,
908 const llvm::BitVector &portIndices,
909 bool supportsEmptyAttr) {
910 if (supportsEmptyAttr && domainInfoAttr.empty())
911 return domainInfoAttr;
914 SmallVector<unsigned> indexMap(portIndices.size());
916 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
917 indexMap[i] = i - deleted;
924 auto getEmpty = [&]() {
926 eEmpty = ArrayAttr::get(
context, {});
931 SmallVector<Attribute> newDomainInfo;
932 newDomainInfo.reserve(portIndices.size() - portIndices.count());
933 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
935 if (portIndices.test(i))
938 if (domainInfoAttr.empty()) {
939 newDomainInfo.push_back(getEmpty());
942 auto attr = domainInfoAttr[i];
944 auto domains = dyn_cast<ArrayAttr>(attr);
945 if (!domains || domains.empty()) {
946 newDomainInfo.push_back(attr);
950 SmallVector<Attribute> newDomains;
951 for (
auto domain : domains) {
953 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
954 if (portIndices.test(oldIdx))
957 auto newIdx = indexMap[oldIdx];
958 if (oldIdx == newIdx) {
959 newDomains.push_back(domain);
963 newDomains.push_back(IntegerAttr::get(
964 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
966 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
969 return ArrayAttr::get(
context, newDomainInfo);
973static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
974 if (portIndices.none())
978 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
979 ArrayRef<Attribute> portNames = op.getPortNames();
980 ArrayRef<Attribute> portTypes = op.getPortTypes();
981 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
982 ArrayRef<Attribute> portSyms = op.getPortSymbols();
983 ArrayRef<Attribute> portLocs = op.getPortLocations();
984 ArrayRef<Attribute> portDomains = op.getDomainInfo();
985 auto numPorts = op.getNumPorts();
987 assert(portDirections.size() == numPorts);
988 assert(portNames.size() == numPorts);
989 assert(portAnnos.size() == numPorts || portAnnos.empty());
990 assert(portTypes.size() == numPorts);
991 assert(portSyms.size() == numPorts || portSyms.empty());
992 assert(portLocs.size() == numPorts);
993 assert(portDomains.size() == numPorts || portDomains.empty());
995 SmallVector<bool> newPortDirections =
996 removeElementsAtIndices<bool>(portDirections, portIndices);
997 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1005 op->setAttr(
"portDirections",
1007 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1008 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1009 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1010 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1011 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1012 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1013 op->setAttr(
"domainInfo",
1015 portIndices,
true));
1018void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1019 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1022void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1023 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1026void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1027 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1030void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1031 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1038void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1039 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1043 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1046 auto &[index, port] = ports[i];
1047 body->insertArgument(index + i, port.type, port.loc);
1051void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1052 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1055void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1056 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1062void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1063 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1066template <
typename OpTy>
1068 StringAttr name, ArrayRef<PortInfo> ports) {
1070 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1071 properties.setSymName(name);
1074 SmallVector<Direction, 4> portDirections;
1075 SmallVector<Attribute, 4> portNames, portTypes, portSyms, portLocs,
1077 portDirections.reserve(ports.size());
1078 portNames.reserve(ports.size());
1079 portTypes.reserve(ports.size());
1080 portSyms.reserve(ports.size());
1081 portLocs.reserve(ports.size());
1082 portDomains.reserve(ports.size());
1084 for (
const auto &port : ports) {
1085 portDirections.push_back(port.direction);
1086 portNames.push_back(port.name);
1087 portTypes.push_back(TypeAttr::get(port.type));
1088 portSyms.push_back(port.sym);
1089 portLocs.push_back(port.loc);
1090 portDomains.push_back(port.domains);
1092 if (llvm::all_of(portDomains, [](Attribute attr) {
1095 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1096 return arrayAttr.empty();
1099 portDomains.clear();
1101 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1104 properties.setPortDirections(
1106 properties.setPortNames(builder.getArrayAttr(portNames));
1107 properties.setPortTypes(builder.getArrayAttr(portTypes));
1108 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1109 properties.setPortLocations(builder.getArrayAttr(portLocs));
1110 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1115template <
typename OpTy>
1117 StringAttr name, ArrayRef<PortInfo> ports,
1118 ArrayAttr annotations, ArrayAttr layers) {
1119 buildModuleLike<OpTy>(builder, result, name, ports);
1120 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1123 annotations = builder.getArrayAttr({});
1124 properties.setAnnotations(annotations);
1128 SmallVector<Attribute, 4> portAnnotations;
1129 for (
const auto &port : ports)
1130 portAnnotations.push_back(port.annotations.getArrayAttr());
1131 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1132 return cast<ArrayAttr>(attr).empty();
1134 portAnnotations.clear();
1135 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1139 layers = builder.getArrayAttr({});
1140 properties.setLayers(layers);
1143template <
typename OpTy>
1144static void buildClass(OpBuilder &builder, OperationState &result,
1145 StringAttr name, ArrayRef<PortInfo> ports) {
1146 return buildModuleLike<OpTy>(builder, result, name, ports);
1149void FModuleOp::build(OpBuilder &builder, OperationState &result,
1150 StringAttr name, ConventionAttr convention,
1151 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1153 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1154 auto &properties = result.getOrAddProperties<Properties>();
1155 properties.setConvention(convention);
1158 auto *bodyRegion = result.regions[0].get();
1160 bodyRegion->push_back(body);
1163 for (
auto &elt : ports)
1164 body->addArgument(elt.type, elt.loc);
1167void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1168 StringAttr name, ConventionAttr convention,
1169 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1170 StringRef defnameAttr, ArrayAttr annotations,
1171 ArrayAttr parameters, ArrayAttr layers,
1172 ArrayAttr externalRequirements) {
1173 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1174 auto &properties = result.getOrAddProperties<Properties>();
1175 properties.setConvention(convention);
1177 knownLayers = builder.getArrayAttr({});
1178 properties.setKnownLayers(knownLayers);
1179 if (!defnameAttr.empty())
1180 properties.setDefname(builder.getStringAttr(defnameAttr));
1182 parameters = builder.getArrayAttr({});
1183 properties.setParameters(parameters);
1184 if (externalRequirements)
1185 properties.setExternalRequirements(externalRequirements);
1188void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1189 StringAttr name, ArrayRef<PortInfo> ports,
1190 StringRef intrinsicNameStr, ArrayAttr annotations,
1191 ArrayAttr parameters, ArrayAttr layers) {
1192 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1193 auto &properties = result.getOrAddProperties<Properties>();
1194 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1196 parameters = builder.getArrayAttr({});
1197 properties.setParameters(parameters);
1200void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1201 StringAttr name, ArrayRef<PortInfo> ports,
1202 uint32_t numReadPorts, uint32_t numWritePorts,
1203 uint32_t numReadWritePorts, uint32_t dataWidth,
1204 uint32_t maskBits, uint32_t readLatency,
1205 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1206 ArrayAttr annotations, ArrayAttr layers) {
1207 auto *
context = builder.getContext();
1208 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1209 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1210 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1211 auto &properties = result.getOrAddProperties<Properties>();
1212 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1213 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1214 properties.setNumReadWritePorts(
1215 IntegerAttr::get(ui32Type, numReadWritePorts));
1216 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1217 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1218 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1219 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1220 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1221 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1222 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1239 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1240 ArrayRef<Attribute> portAnnotations,
1241 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1242 ArrayRef<Attribute> domainInfo) {
1245 bool printedNamesDontMatch =
false;
1247 mlir::OpPrintingFlags flags;
1250 DenseMap<unsigned, std::string> ssaNames;
1251 auto getSsaName = [&](
unsigned idx) -> StringRef {
1253 auto itr = ssaNames.find(idx);
1254 if (itr != ssaNames.end())
1255 return itr->getSecond();
1259 SmallString<32> resultNameStr;
1261 llvm::raw_svector_ostream tmpStream(resultNameStr);
1262 p.printOperand(block->getArgument(idx), tmpStream);
1265 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1266 if (tmpStream.str().drop_front() != portName)
1267 printedNamesDontMatch =
true;
1268 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1271 auto name = cast<StringAttr>(portNames[idx]).getValue();
1272 return ssaNames.insert({idx, name.str()}).first->getSecond();
1278 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1287 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1291 p.printKeywordOrString(getSsaName(i));
1296 p.printType(portType);
1299 if (!portSyms.empty()) {
1300 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1302 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1307 if (!domainInfo.empty()) {
1308 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1311 auto domains = cast<ArrayAttr>(domainInfo[i]);
1312 if (!domains.empty()) {
1314 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1315 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1324 if (!portAnnotations.empty() &&
1325 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1327 p.printAttribute(portAnnotations[i]);
1334 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1335 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1339 return printedNamesDontMatch;
1345 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1346 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1347 SmallVectorImpl<Direction> &portDirections,
1348 SmallVectorImpl<Attribute> &portNames,
1349 SmallVectorImpl<Attribute> &portTypes,
1350 SmallVectorImpl<Attribute> &portAnnotations,
1351 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1352 SmallVectorImpl<Attribute> &domains) {
1353 auto *
context = parser.getContext();
1356 DenseMap<Attribute, size_t> domainIndex;
1359 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1360 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1362 auto parseArgument = [&]() -> ParseResult {
1364 if (succeeded(parser.parseOptionalKeyword(
"out")))
1365 portDirections.push_back(Direction::Out);
1366 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1367 portDirections.push_back(Direction::In);
1374 auto portIdx = portNames.size();
1376 if (hasSSAIdentifiers) {
1377 OpAsmParser::Argument arg;
1378 if (parser.parseArgument(arg))
1380 entryArgs.push_back(arg);
1384 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1385 "Unknown MLIR name");
1386 if (
isdigit(arg.ssaName.name[1]))
1387 portNames.push_back(StringAttr::get(
context,
""));
1389 portNames.push_back(
1390 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1393 irLoc = arg.ssaName.location;
1397 irLoc = parser.getCurrentLocation();
1398 std::string portName;
1399 if (parser.parseKeywordOrString(&portName))
1401 portNames.push_back(StringAttr::get(
context, portName));
1406 if (parser.parseColonType(portType))
1408 portTypes.push_back(TypeAttr::get(portType));
1409 if (isa<DomainType>(portType))
1410 domainIndex[portNames.back()] = portIdx;
1412 if (hasSSAIdentifiers)
1413 entryArgs.back().type = portType;
1416 if (supportsSymbols) {
1417 hw::InnerSymAttr innerSymAttr;
1418 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1419 NamedAttrList dummyAttrs;
1420 if (parser.parseCustomAttributeWithFallback(
1421 innerSymAttr, ::mlir::Type{},
1423 return ::mlir::failure();
1426 portSyms.push_back(innerSymAttr);
1434 Attribute domainInfo;
1435 if (supportsDomains) {
1436 if (isa<DomainType>(portType)) {
1437 FlatSymbolRefAttr domainKind;
1440 domainInfo = domainKind;
1441 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1442 auto result = parser.parseCommaSeparatedList(
1443 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1445 if (hasSSAIdentifiers) {
1446 OpAsmParser::Argument arg;
1447 if (parser.parseArgument(arg))
1450 StringAttr::get(
context, arg.ssaName.name.drop_front());
1452 std::string portName;
1453 if (parser.parseKeywordOrString(&portName))
1455 argName = StringAttr::get(
context, portName);
1457 domainStrings[portIdx].push_back({argName, irLoc});
1464 domains.push_back(domainInfo);
1468 auto parseResult = parser.parseOptionalAttribute(annos);
1469 if (!parseResult.has_value())
1470 annos = parser.getBuilder().getArrayAttr({});
1471 else if (failed(*parseResult))
1473 portAnnotations.push_back(annos);
1476 std::optional<Location> maybeLoc;
1477 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1479 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1480 portLocs.push_back(loc);
1481 if (hasSSAIdentifiers)
1482 entryArgs.back().sourceLoc = loc;
1491 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1497 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1502 SmallVector<Attribute> portDomains;
1503 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1504 auto index = domainIndex.find(domainName);
1505 if (index == domainIndex.end()) {
1506 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1509 portDomains.push_back(IntegerAttr::get(
1510 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1512 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1520 ArrayAttr parameters) {
1521 if (!parameters || parameters.empty())
1525 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1526 auto paramAttr = cast<ParamDeclAttr>(param);
1527 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1528 if (
auto value = paramAttr.getValue()) {
1530 p.printAttributeWithoutType(value);
1540 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1541 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1542 p << visibility.getValue() <<
' ';
1545 p.printSymbolName(op.getModuleName());
1552 Block *body =
nullptr;
1553 if (!op->getRegion(0).empty())
1554 body = &op->getRegion(0).front();
1557 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1558 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1559 op.getDomainInfo());
1561 SmallVector<StringRef, 13> omittedAttrs = {
1562 "sym_name",
"portDirections",
"portTypes",
1563 "portAnnotations",
"portSymbols",
"portLocations",
1564 "parameters", visibilityAttrName,
"domainInfo"};
1566 if (op.getConvention() == Convention::Internal)
1567 omittedAttrs.push_back(
"convention");
1571 if (!needPortNamesAttr)
1572 omittedAttrs.push_back(
"portNames");
1575 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1576 omittedAttrs.push_back(
"annotations");
1579 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1580 if (knownLayers.empty())
1581 omittedAttrs.push_back(
"knownLayers");
1584 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1586 omittedAttrs.push_back(
"layers");
1589 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1590 if (extReqs.empty())
1591 omittedAttrs.push_back(
"externalRequirements");
1593 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1602void FModuleOp::print(OpAsmPrinter &p) {
1608 Region &fbody = getBody();
1609 if (!fbody.empty()) {
1611 p.printRegion(fbody,
false,
1623 SmallVectorImpl<Attribute> ¶meters) {
1625 return parser.parseCommaSeparatedList(
1626 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1631 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1635 if (succeeded(parser.parseOptionalEqual())) {
1636 if (parser.parseAttribute(value, type))
1640 auto &builder = parser.getBuilder();
1641 parameters.push_back(ParamDeclAttr::get(
1642 builder.getContext(), builder.getStringAttr(name), type, value));
1649 ArrayAttr ¶meters) {
1650 SmallVector<Attribute> parseParameters;
1654 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1659template <
typename Properties,
typename =
void>
1662template <
typename Properties>
1664 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1665 : std::true_type {};
1667template <
typename OpTy>
1669 OperationState &result,
1670 bool hasSSAIdentifiers) {
1671 auto *
context = result.getContext();
1672 auto &builder = parser.getBuilder();
1673 using Properties =
typename OpTy::Properties;
1674 auto &properties = result.getOrAddProperties<Properties>();
1678 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1681 StringAttr nameAttr;
1682 if (parser.parseSymbolName(nameAttr))
1684 properties.setSymName(nameAttr);
1688 SmallVector<Attribute, 4> parameters;
1691 properties.setParameters(builder.getArrayAttr(parameters));
1695 SmallVector<OpAsmParser::Argument> entryArgs;
1696 SmallVector<Direction, 4> portDirections;
1697 SmallVector<Attribute, 4> portNames;
1698 SmallVector<Attribute, 4> portTypes;
1699 SmallVector<Attribute, 4> portAnnotations;
1700 SmallVector<Attribute, 4> portSyms;
1701 SmallVector<Attribute, 4> portLocs;
1702 SmallVector<Attribute, 4> domains;
1704 true, entryArgs, portDirections,
1705 portNames, portTypes, portAnnotations, portSyms,
1710 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1713 assert(portNames.size() == portTypes.size());
1719 properties.setPortDirections(
1723 properties.setPortNames(builder.getArrayAttr(portNames));
1726 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1730 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1731 return !cast<ArrayAttr>(anno).empty();
1733 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1735 properties.setPortAnnotations(builder.getArrayAttr({}));
1738 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1739 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1742 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1745 properties.setAnnotations(builder.getArrayAttr({}));
1748 if (llvm::all_of(domains, [&](Attribute attr) {
1749 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1750 return arrayAttr && arrayAttr.empty();
1752 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1754 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1757 auto *body = result.addRegion();
1759 if (hasSSAIdentifiers) {
1760 if (parser.parseRegion(*body, entryArgs))
1763 body->push_back(
new Block());
1768ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1769 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1772 auto &properties = result.getOrAddProperties<Properties>();
1773 properties.setConvention(
1774 ConventionAttr::get(result.getContext(), Convention::Internal));
1775 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1779ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1780 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1783 auto &properties = result.getOrAddProperties<Properties>();
1784 properties.setConvention(
1785 ConventionAttr::get(result.getContext(), Convention::Internal));
1786 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1790ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1791 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1795ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1796 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1800LogicalResult FModuleOp::verify() {
1803 auto portTypes = getPortTypes();
1804 auto portLocs = getPortLocations();
1805 auto numPorts = portTypes.size();
1808 if (body->getNumArguments() != numPorts)
1809 return emitOpError(
"entry block must have ")
1810 << numPorts <<
" arguments to match module signature";
1813 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1814 if (arg.getType() != cast<TypeAttr>(type).getValue())
1815 return emitOpError(
"block argument types should match signature types");
1816 if (arg.getLoc() != cast<LocationAttr>(loc))
1818 "block argument locations should match signature locations");
1824LogicalResult FExtModuleOp::verify() {
1825 auto params = getParameters();
1827 auto checkParmValue = [&](Attribute elt) ->
bool {
1828 auto param = cast<ParamDeclAttr>(elt);
1829 auto value = param.getValue();
1830 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1832 emitError() <<
"has unknown extmodule parameter value '"
1833 << param.getName().getValue() <<
"' = " << value;
1837 if (!llvm::all_of(params, checkParmValue))
1842 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1845 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1846 for (
auto attr : getPortTypes()) {
1847 auto type = cast<TypeAttr>(attr).getValue();
1848 if (
auto refType = type_dyn_cast<RefType>(type))
1849 if (
auto layer = refType.getLayer())
1850 referenced.insert(layer);
1854 "references unknown layers",
"unknown layers");
1857LogicalResult FIntModuleOp::verify() {
1858 auto params = getParameters();
1862 auto checkParmValue = [&](Attribute elt) ->
bool {
1863 auto param = cast<ParamDeclAttr>(elt);
1864 auto value = param.getValue();
1865 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1867 emitError() <<
"has unknown intmodule parameter value '"
1868 << param.getName().getValue() <<
"' = " << value;
1872 if (!llvm::all_of(params, checkParmValue))
1879 CircuitOp circuitOp,
1880 SymbolTableCollection &symbolTable,
1882 auto layer = refType.getLayer();
1885 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1887 return emitError(loc) << start <<
" associated with layer '" << layer
1888 <<
"', but this layer was not defined";
1889 if (!isa<LayerOp>(layerOp)) {
1890 auto diag = emitError(loc)
1891 << start <<
" associated with layer '" << layer
1892 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1893 << LayerOp::getOperationName() <<
"' op";
1894 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1900 SymbolTableCollection &symbolTable) {
1902 auto circuitOp =
module->getParentOfType<CircuitOp>();
1903 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1904 auto type =
module.getPortType(i);
1906 if (
auto refType = type_dyn_cast<RefType>(type)) {
1908 refType, module.getPortLocation(i), circuitOp, symbolTable,
1909 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1914 if (
auto classType = dyn_cast<ClassType>(type)) {
1915 auto className = classType.getNameAttr();
1916 auto classOp = dyn_cast_or_null<ClassLike>(
1917 symbolTable.lookupSymbolIn(circuitOp, className));
1919 return module.emitOpError() << "references unknown class " << className;
1922 if (failed(classOp.verifyType(classType,
1923 [&]() { return module.emitOpError(); })))
1928 if (isa<DomainType>(type)) {
1929 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1930 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1931 if (!dyn_cast_or_null<DomainOp>(
1932 symbolTable.lookupSymbolIn(circuitOp, kind)))
1933 return mlir::emitError(module.getPortLocation(i))
1934 <<
"domain port '" <<
module.getPortName(i)
1935 << "' has undefined domain kind '" << kind.getValue() << "'";
1942LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1946 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1947 for (
auto layer : getLayers()) {
1948 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1949 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1956FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1960 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1961 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1962 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1963 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1965 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1966 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1967 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1974FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1979FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1983void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1988void FExtModuleOp::getAsmBlockArgumentNames(
1993StringAttr FExtModuleOp::getExtModuleNameAttr() {
1994 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1996 return getNameAttr();
1999StringRef FExtModuleOp::getExtModuleName() {
2000 if (
auto defname = getDefname(); defname && !defname->empty())
2005void FIntModuleOp::getAsmBlockArgumentNames(
2010void FMemModuleOp::getAsmBlockArgumentNames(
2015ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2017ArrayAttr FModuleOp::getParameters() {
return {}; }
2019Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2021ConventionAttr FIntModuleOp::getConventionAttr() {
2022 return ConventionAttr::get(getContext(), getConvention());
2025Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2027ConventionAttr FMemModuleOp::getConventionAttr() {
2028 return ConventionAttr::get(getContext(), getConvention());
2036 ClassLike classOp, ClassType type,
2037 function_ref<InFlightDiagnostic()> emitError) {
2039 auto name = type.getNameAttr().getAttr();
2040 auto expectedName = classOp.getModuleNameAttr();
2041 if (name != expectedName)
2042 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2045 auto elements = type.getElements();
2047 auto expectedNumElements = classOp.getNumPorts();
2049 return emitError() <<
"has wrong number of ports, got " <<
numElements
2050 <<
", expected " << expectedNumElements;
2052 auto portNames = classOp.getPortNames();
2053 auto portDirections = classOp.getPortDirections();
2054 auto portTypes = classOp.getPortTypes();
2057 auto element = elements[i];
2059 auto name = element.name;
2060 auto expectedName = portNames[i];
2061 if (name != expectedName)
2062 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2063 <<
", expected " << expectedName;
2065 auto direction = element.direction;
2066 auto expectedDirection =
Direction(portDirections[i]);
2067 if (direction != expectedDirection)
2068 return emitError() <<
"port " << name <<
" has wrong direction, got "
2072 auto type = element.type;
2073 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2074 if (type != expectedType)
2075 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2076 <<
", expected " << expectedType;
2083 auto n = classOp.getNumPorts();
2084 SmallVector<ClassElement> elements;
2085 elements.reserve(n);
2086 for (
size_t i = 0; i < n; ++i)
2087 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2088 classOp.getPortDirection(i)});
2089 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2090 return ClassType::get(name, elements);
2093template <
typename OpTy>
2095 bool hasSSAIdentifiers) {
2096 auto *
context = result.getContext();
2097 auto &builder = parser.getBuilder();
2098 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2102 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2105 StringAttr nameAttr;
2106 if (parser.parseSymbolName(nameAttr))
2108 properties.setSymName(nameAttr);
2111 SmallVector<OpAsmParser::Argument> entryArgs;
2112 SmallVector<Direction, 4> portDirections;
2113 SmallVector<Attribute, 4> portNames;
2114 SmallVector<Attribute, 4> portTypes;
2115 SmallVector<Attribute, 4> portAnnotations;
2116 SmallVector<Attribute, 4> portSyms;
2117 SmallVector<Attribute, 4> portLocs;
2118 SmallVector<Attribute, 4> domains;
2121 entryArgs, portDirections, portNames, portTypes,
2122 portAnnotations, portSyms, portLocs, domains))
2126 for (
auto annos : portAnnotations)
2127 if (!cast<ArrayAttr>(annos).empty())
2131 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2134 assert(portNames.size() == portTypes.size());
2140 properties.setPortDirections(
2144 properties.setPortNames(builder.getArrayAttr(portNames));
2147 properties.setPortTypes(builder.getArrayAttr(portTypes));
2150 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2151 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2154 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2160 auto *bodyRegion = result.addRegion();
2162 if (hasSSAIdentifiers) {
2163 if (parser.parseRegion(*bodyRegion, entryArgs))
2165 if (bodyRegion->empty())
2166 bodyRegion->push_back(
new Block());
2176 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2177 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2178 p << visibility.getValue() <<
' ';
2181 p.printSymbolName(op.getName());
2185 Region ®ion = op->getRegion(0);
2186 Block *body =
nullptr;
2187 if (!region.empty())
2188 body = ®ion.front();
2191 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2192 {}, op.getPortSymbols(), op.getPortLocations(), {});
2195 SmallVector<StringRef, 8> omittedAttrs = {
2196 "sym_name",
"portNames",
"portTypes",
"portDirections",
2197 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2201 if (!needPortNamesAttr)
2202 omittedAttrs.push_back(
"portNames");
2204 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2207 if (!region.empty()) {
2209 auto printEntryBlockArgs =
false;
2210 auto printBlockTerminators =
false;
2211 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2219void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2220 ArrayRef<PortInfo> ports) {
2223 [](
const auto &port) {
return port.annotations.empty(); }) &&
2224 "class ports may not have annotations");
2226 buildClass<ClassOp>(builder, result, name, ports);
2229 auto *bodyRegion = result.regions[0].get();
2231 bodyRegion->push_back(body);
2234 for (
auto &elt : ports)
2235 body->addArgument(elt.type, elt.loc);
2238void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2239 ::mlir::OperationState &odsState, Twine name,
2240 mlir::ArrayRef<mlir::StringRef> fieldNames,
2241 mlir::ArrayRef<mlir::Type> fieldTypes) {
2243 SmallVector<PortInfo, 10> ports;
2244 ports.reserve(fieldNames.size() * 2);
2245 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2246 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2248 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2251 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2253 auto &body = odsState.regions[0]->getBlocks().front();
2254 auto prevLoc = odsBuilder.saveInsertionPoint();
2255 odsBuilder.setInsertionPointToEnd(&body);
2256 auto args = body.getArguments();
2257 auto loc = odsState.location;
2258 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2259 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2261 odsBuilder.restoreInsertionPoint(prevLoc);
2263void ClassOp::print(OpAsmPrinter &p) {
2267ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2268 auto hasSSAIdentifiers =
true;
2269 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2272LogicalResult ClassOp::verify() {
2274 auto type = operand.getType();
2275 if (!isa<PropertyType>(type)) {
2276 emitOpError(
"ports on a class must be properties");
2285ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2289void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2294SmallVector<PortInfo> ClassOp::getPorts() {
2295 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2298void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2299 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2303void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2304 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2307Convention ClassOp::getConvention() {
return Convention::Internal; }
2309ConventionAttr ClassOp::getConventionAttr() {
2310 return ConventionAttr::get(getContext(), getConvention());
2313ArrayAttr ClassOp::getParameters() {
return {}; }
2315ArrayAttr ClassOp::getPortAnnotationsAttr() {
2316 return ArrayAttr::get(getContext(), {});
2319ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2321void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2322 llvm_unreachable(
"classes do not support annotations");
2325ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2327ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2329SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2330 return ::getPortListImpl(*
this);
2334 return ::getPortImpl(*
this, idx);
2337BlockArgument ClassOp::getArgument(
size_t portNumber) {
2341bool ClassOp::canDiscardOnUseEmpty() {
2352void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2353 StringAttr name, ArrayRef<PortInfo> ports) {
2356 [](
const auto &port) {
return port.annotations.empty(); }) &&
2357 "class ports may not have annotations");
2358 buildClass<ClassOp>(builder, result, name, ports);
2361void ExtClassOp::print(OpAsmPrinter &p) {
2365ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2366 auto hasSSAIdentifiers =
false;
2367 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2371ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2375void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2380SmallVector<PortInfo> ExtClassOp::getPorts() {
2381 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2384void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2385 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2388void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2389 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2392Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2394ConventionAttr ExtClassOp::getConventionAttr() {
2395 return ConventionAttr::get(getContext(), getConvention());
2398ArrayAttr ExtClassOp::getLayersAttr() {
2399 return ArrayAttr::get(getContext(), {});
2402ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2404ArrayAttr ExtClassOp::getParameters() {
return {}; }
2406ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2407 return ArrayAttr::get(getContext(), {});
2410ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2412void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2413 llvm_unreachable(
"classes do not support annotations");
2416SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2417 return ::getPortListImpl(*
this);
2421 return ::getPortImpl(*
this, idx);
2424bool ExtClassOp::canDiscardOnUseEmpty() {
2435void InstanceOp::build(
2436 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2437 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2438 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2439 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2440 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2441 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2442 build(builder, result, resultTypes, moduleName, name, nameKind,
2443 portDirections, portNames, domainInfo, annotations, portAnnotations,
2444 layers, lowerToBind, doNotPrint,
2445 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2448void InstanceOp::build(
2449 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2450 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2451 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2452 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2453 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2454 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2455 result.addTypes(resultTypes);
2456 result.getOrAddProperties<Properties>().setModuleName(
2457 SymbolRefAttr::get(builder.getContext(), moduleName));
2458 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2459 result.getOrAddProperties<Properties>().setPortDirections(
2461 result.getOrAddProperties<Properties>().setPortNames(
2462 builder.getArrayAttr(portNames));
2464 if (domainInfo.empty()) {
2465 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2466 builder.getArrayAttr({}));
2467 result.getOrAddProperties<Properties>().setDomainInfo(
2468 builder.getArrayAttr(domainInfoVec));
2470 assert(domainInfo.size() == resultTypes.size());
2471 result.getOrAddProperties<Properties>().setDomainInfo(
2472 builder.getArrayAttr(domainInfo));
2475 result.getOrAddProperties<Properties>().setAnnotations(
2476 builder.getArrayAttr(annotations));
2477 result.getOrAddProperties<Properties>().setLayers(
2478 builder.getArrayAttr(layers));
2480 result.getOrAddProperties<Properties>().setLowerToBind(
2481 builder.getUnitAttr());
2483 result.getOrAddProperties<Properties>().setDoNotPrint(
2484 builder.getUnitAttr());
2486 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2488 result.getOrAddProperties<Properties>().setNameKind(
2489 NameKindEnumAttr::get(builder.getContext(), nameKind));
2491 if (portAnnotations.empty()) {
2492 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2493 builder.getArrayAttr({}));
2494 result.getOrAddProperties<Properties>().setPortAnnotations(
2495 builder.getArrayAttr(portAnnotationsVec));
2497 assert(portAnnotations.size() == resultTypes.size());
2498 result.getOrAddProperties<Properties>().setPortAnnotations(
2499 builder.getArrayAttr(portAnnotations));
2503void InstanceOp::build(OpBuilder &builder, OperationState &result,
2504 FModuleLike module, StringRef name,
2505 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2506 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2507 bool doNotPrint, hw::InnerSymAttr innerSym) {
2510 SmallVector<Type> resultTypes;
2511 resultTypes.reserve(module.getNumPorts());
2513 module.getPortTypes(), std::back_inserter(resultTypes),
2514 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2519 ArrayAttr portAnnotationsAttr;
2520 if (portAnnotations.empty()) {
2521 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2522 resultTypes.size(), builder.getArrayAttr({})));
2524 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2526 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2527 if (domainInfoAttr.empty()) {
2528 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2529 resultTypes.size(), builder.getArrayAttr({})));
2533 builder, result, resultTypes,
2534 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2535 builder.getStringAttr(name),
2536 NameKindEnumAttr::get(builder.getContext(), nameKind),
2537 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2538 builder.getArrayAttr(annotations), portAnnotationsAttr,
2539 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2540 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2543void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2544 ArrayRef<PortInfo> ports, StringRef moduleName,
2545 StringRef name, NameKindEnum nameKind,
2546 ArrayRef<Attribute> annotations,
2547 ArrayRef<Attribute> layers,
bool lowerToBind,
2548 bool doNotPrint, hw::InnerSymAttr innerSym) {
2550 SmallVector<Type> newResultTypes;
2551 SmallVector<Direction> newPortDirections;
2552 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2553 newResultTypes.reserve(ports.size());
2554 newPortDirections.reserve(ports.size());
2555 newPortNames.reserve(ports.size());
2556 newPortAnnotations.reserve(ports.size());
2557 newDomainInfo.reserve(ports.size());
2559 for (
auto &p : ports) {
2560 newResultTypes.push_back(p.type);
2561 newPortDirections.push_back(p.direction);
2562 newPortNames.push_back(p.name);
2563 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2565 newDomainInfo.push_back(p.domains);
2567 newDomainInfo.push_back(builder.getArrayAttr({}));
2570 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2571 newPortDirections, newPortNames, newDomainInfo, annotations,
2572 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2575LogicalResult InstanceOp::verify() {
2578 SmallVector<SymbolRefAttr> missingLayers;
2579 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2581 missingLayers.push_back(layer);
2583 if (missingLayers.empty())
2587 emitOpError(
"ambient layers are insufficient to instantiate module");
2588 auto ¬e = diag.attachNote();
2589 note <<
"missing layer requirements: ";
2590 interleaveComma(missingLayers, note);
2595 Operation *op1, Operation *op2,
2596 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2598 size_t n = insertions.size();
2599 size_t inserted = 0;
2600 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2601 while (inserted < n) {
2602 auto &[index, portInfo] = insertions[inserted];
2607 auto r1 = op1->getResult(i);
2608 auto r2 = op2->getResult(i + inserted);
2609 r1.replaceAllUsesWith(r2);
2614 const llvm::BitVector &erasures) {
2617 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2618 auto r1 = op1->getResult(i);
2620 assert(r1.use_empty() &&
"removed instance port has uses");
2624 auto r2 = op2->getResult(i - erased);
2625 r1.replaceAllUsesWith(r2);
2629InstanceOp InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2630 assert(erasures.size() >= getNumResults() &&
2631 "erasures is not at least as large as getNumResults()");
2633 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2634 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2635 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2637 SmallVector<Attribute> newPortNames =
2639 SmallVector<Attribute> newPortAnnotations =
2641 ArrayAttr newDomainInfo =
2645 OpBuilder builder(*
this);
2646 auto clone = InstanceOp::create(
2647 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2648 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2649 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2650 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2652 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2653 clone->setAttr(
"output_file", outputFile);
2658InstanceOp InstanceOp::cloneWithErasedPortsAndReplaceUses(
2659 const llvm::BitVector &erasures) {
2660 auto clone = cloneWithErasedPorts(erasures);
2665ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2666 assert(portIdx < getNumResults() &&
2667 "index should be smaller than result number");
2668 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2671void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2672 assert(annotations.size() == getNumResults() &&
2673 "number of annotations is not equal to result number");
2674 (*this)->setAttr(
"portAnnotations",
2675 ArrayAttr::get(getContext(), annotations));
2678Attribute InstanceOp::getPortDomain(
unsigned portIdx) {
2679 assert(portIdx < getNumResults() &&
2680 "index should be smaller than result number");
2681 return getDomainInfo()[portIdx];
2684InstanceOp InstanceOp::cloneWithInsertedPorts(
2685 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2689 auto oldPortCount = getNumResults();
2690 auto numInsertions = insertions.size();
2691 auto newPortCount = oldPortCount + numInsertions;
2693 SmallVector<Direction> newPortDirections;
2694 SmallVector<Attribute> newPortNames;
2695 SmallVector<Type> newPortTypes;
2696 SmallVector<Attribute> newPortAnnos;
2697 SmallVector<Attribute> newDomainInfo;
2699 newPortDirections.reserve(newPortCount);
2700 newPortNames.reserve(newPortCount);
2701 newPortTypes.reserve(newPortCount);
2702 newPortAnnos.reserve(newPortCount);
2703 newDomainInfo.reserve(newPortCount);
2705 SmallVector<unsigned> indexMap(oldPortCount);
2707 size_t inserted = 0;
2708 for (
size_t i = 0; i < oldPortCount; ++i) {
2709 while (inserted < numInsertions) {
2710 auto &[index,
info] = insertions[inserted];
2716 newPortDirections.push_back(
info.direction);
2717 newPortNames.push_back(
info.name);
2718 newPortTypes.push_back(
info.type);
2719 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2720 newDomainInfo.push_back(domains);
2724 newPortDirections.push_back(getPortDirection(i));
2725 newPortNames.push_back(getPortNameAttr(i));
2726 newPortTypes.push_back(getType(i));
2727 newPortAnnos.push_back(getPortAnnotation(i));
2728 newDomainInfo.push_back(getDomainInfo()[i]);
2729 indexMap[i] = i + inserted;
2732 while (inserted < numInsertions) {
2733 auto &[index,
info] = insertions[inserted];
2736 newPortDirections.push_back(
info.direction);
2737 newPortNames.push_back(
info.name);
2738 newPortTypes.push_back(
info.type);
2739 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2740 newDomainInfo.push_back(domains);
2744 OpBuilder builder(*
this);
2745 auto clone = InstanceOp::create(
2746 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2747 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2748 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2749 getDoNotPrint(), getInnerSymAttr());
2751 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2752 clone->setAttr(
"output_file", outputFile);
2757InstanceOp InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2758 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2759 auto clone = cloneWithInsertedPorts(insertions);
2764LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2766 getModuleNameAttr());
2769StringRef InstanceOp::getInstanceName() {
return getName(); }
2771StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2773void InstanceOp::print(OpAsmPrinter &p) {
2776 p.printKeywordOrString(
getName());
2777 if (
auto attr = getInnerSymAttr()) {
2779 p.printSymbolName(attr.getSymName());
2781 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2782 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2785 SmallVector<StringRef, 10> omittedAttrs = {
2786 "moduleName",
"name",
"portDirections",
2787 "portNames",
"portTypes",
"portAnnotations",
2788 "inner_sym",
"nameKind",
"domainInfo"};
2789 if (getAnnotations().
empty())
2790 omittedAttrs.push_back(
"annotations");
2791 if (getLayers().
empty())
2792 omittedAttrs.push_back(
"layers");
2793 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2797 p.printSymbolName(getModuleName());
2800 SmallVector<Attribute> portTypes;
2801 portTypes.reserve(getNumResults());
2802 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2806 getPortNames().getValue(), portTypes,
2807 getPortAnnotations().getValue(), {}, {},
2808 getDomainInfo().getValue());
2811ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2812 auto *
context = parser.getContext();
2813 auto &properties = result.getOrAddProperties<Properties>();
2816 hw::InnerSymAttr innerSymAttr;
2817 FlatSymbolRefAttr moduleName;
2818 SmallVector<OpAsmParser::Argument> entryArgs;
2819 SmallVector<Direction, 4> portDirections;
2820 SmallVector<Attribute, 4> portNames;
2821 SmallVector<Attribute, 4> portTypes;
2822 SmallVector<Attribute, 4> portAnnotations;
2823 SmallVector<Attribute, 4> portSyms;
2824 SmallVector<Attribute, 4> portLocs;
2825 SmallVector<Attribute, 4> domains;
2826 NameKindEnumAttr nameKind;
2828 if (parser.parseKeywordOrString(&name))
2830 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2831 if (parser.parseCustomAttributeWithFallback(
2832 innerSymAttr, ::mlir::Type{},
2834 result.attributes)) {
2835 return ::mlir::failure();
2839 parser.parseOptionalAttrDict(result.attributes) ||
2840 parser.parseAttribute(moduleName) ||
2843 entryArgs, portDirections, portNames, portTypes,
2844 portAnnotations, portSyms, portLocs, domains))
2850 properties.setModuleName(moduleName);
2851 properties.setName(StringAttr::get(
context, name));
2852 properties.setNameKind(nameKind);
2853 properties.setPortDirections(
2855 properties.setPortNames(ArrayAttr::get(
context, portNames));
2856 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2860 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2861 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2864 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2867 result.types.reserve(portTypes.size());
2869 portTypes, std::back_inserter(result.types),
2870 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2875void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2880 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2881 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2885std::optional<size_t> InstanceOp::getTargetResultIndex() {
2887 return std::nullopt;
2894void InstanceChoiceOp::build(
2895 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2896 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2897 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2898 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2900 SmallVector<Type> resultTypes;
2901 for (Attribute portType : defaultModule.getPortTypes())
2902 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2905 ArrayAttr portAnnotationsAttr;
2906 if (portAnnotations.empty()) {
2907 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2908 resultTypes.size(), builder.getArrayAttr({})));
2910 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2914 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2915 if (domainInfoAttr.empty()) {
2916 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2917 resultTypes.size(), builder.getArrayAttr({})));
2921 SmallVector<Attribute> moduleNames, caseNames;
2922 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2923 for (
auto [caseOption, caseModule] : cases) {
2924 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2925 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2926 {SymbolRefAttr::get(caseOption)}));
2927 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2930 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2931 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2932 NameKindEnumAttr::get(builder.getContext(), nameKind),
2933 defaultModule.getPortDirectionsAttr(),
2934 defaultModule.getPortNamesAttr(), domainInfoAttr,
2935 builder.getArrayAttr(annotations), portAnnotationsAttr,
2936 defaultModule.getLayersAttr(),
2937 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2940void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2941 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2942 ArrayAttr caseNames, StringRef name,
2943 NameKindEnum nameKind, ArrayAttr annotations,
2944 ArrayAttr layers, hw::InnerSymAttr innerSym) {
2946 SmallVector<Type> newResultTypes;
2947 SmallVector<bool> newPortDirections;
2948 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2949 newPortDirections.reserve(ports.size());
2950 newResultTypes.reserve(ports.size());
2951 newPortAnnotations.reserve(ports.size());
2952 newDomainInfo.reserve(ports.size());
2953 newPortNames.reserve(ports.size());
2954 for (
auto &p : ports) {
2955 newResultTypes.push_back(p.type);
2957 newPortDirections.push_back(p.direction == Direction::Out);
2958 newPortNames.push_back(p.name);
2959 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2961 newDomainInfo.push_back(p.domains);
2963 newDomainInfo.push_back(builder.getArrayAttr({}));
2966 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2967 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2968 builder.getArrayAttr(newDomainInfo), annotations,
2969 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2973std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2974 return std::nullopt;
2977StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2979StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2981ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2983 auto moduleNames = getModuleNamesAttr();
2984 SmallVector<Attribute> moduleNameStrings;
2985 moduleNameStrings.reserve(moduleNames.size());
2986 for (
auto moduleName : moduleNames)
2987 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2989 return ArrayAttr::get(getContext(), moduleNameStrings);
2992void InstanceChoiceOp::print(OpAsmPrinter &p) {
2995 p.printKeywordOrString(
getName());
2996 if (
auto attr = getInnerSymAttr()) {
2998 p.printSymbolName(attr.getSymName());
3000 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
3001 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
3004 SmallVector<StringRef, 11> omittedAttrs = {
3005 "moduleNames",
"caseNames",
"name",
3006 "portDirections",
"portNames",
"portTypes",
3007 "portAnnotations",
"inner_sym",
"nameKind",
3009 if (getAnnotations().
empty())
3010 omittedAttrs.push_back(
"annotations");
3011 if (getLayers().
empty())
3012 omittedAttrs.push_back(
"layers");
3013 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
3018 auto moduleNames = getModuleNamesAttr();
3019 auto caseNames = getCaseNamesAttr();
3021 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
3023 p <<
" alternatives ";
3025 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
3027 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3031 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
3032 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
3034 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
3040 SmallVector<Attribute> portTypes;
3041 portTypes.reserve(getNumResults());
3042 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
3045 getPortNames().getValue(), portTypes,
3046 getPortAnnotations().getValue(), {}, {},
3047 getDomainInfo().getValue());
3050ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3051 OperationState &result) {
3052 auto *
context = parser.getContext();
3053 auto &properties = result.getOrAddProperties<Properties>();
3056 hw::InnerSymAttr innerSymAttr;
3057 SmallVector<Attribute> moduleNames;
3058 SmallVector<Attribute> caseNames;
3059 SmallVector<OpAsmParser::Argument> entryArgs;
3060 SmallVector<Direction, 4> portDirections;
3061 SmallVector<Attribute, 4> portNames;
3062 SmallVector<Attribute, 4> portTypes;
3063 SmallVector<Attribute, 4> portAnnotations;
3064 SmallVector<Attribute, 4> portSyms;
3065 SmallVector<Attribute, 4> portLocs;
3066 SmallVector<Attribute, 4> domains;
3067 NameKindEnumAttr nameKind;
3069 if (parser.parseKeywordOrString(&name))
3071 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3072 if (parser.parseCustomAttributeWithFallback(
3073 innerSymAttr, Type{},
3075 result.attributes)) {
3080 parser.parseOptionalAttrDict(result.attributes))
3083 FlatSymbolRefAttr defaultModuleName;
3084 if (parser.parseAttribute(defaultModuleName))
3086 moduleNames.push_back(defaultModuleName);
3090 FlatSymbolRefAttr optionName;
3091 if (parser.parseKeyword(
"alternatives") ||
3092 parser.parseAttribute(optionName) || parser.parseLBrace())
3095 FlatSymbolRefAttr moduleName;
3096 StringAttr caseName;
3097 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3098 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3100 moduleNames.push_back(moduleName);
3101 caseNames.push_back(SymbolRefAttr::get(
3102 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3103 if (failed(parser.parseOptionalComma()))
3106 if (parser.parseRBrace())
3112 entryArgs, portDirections, portNames, portTypes,
3113 portAnnotations, portSyms, portLocs, domains))
3118 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3119 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3120 properties.setName(StringAttr::get(
context, name));
3121 properties.setNameKind(nameKind);
3122 properties.setPortDirections(
3124 properties.setPortNames(ArrayAttr::get(
context, portNames));
3125 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3126 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3130 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3131 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3134 result.types.reserve(portTypes.size());
3136 portTypes, std::back_inserter(result.types),
3137 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3142void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3144 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3145 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3148LogicalResult InstanceChoiceOp::verify() {
3149 if (getCaseNamesAttr().
empty())
3150 return emitOpError() <<
"must have at least one case";
3151 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3152 return emitOpError() <<
"number of referenced modules does not match the "
3153 "number of options";
3158 SmallVector<SymbolRefAttr> missingLayers;
3159 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3161 missingLayers.push_back(layer);
3163 if (missingLayers.empty())
3167 emitOpError(
"ambient layers are insufficient to instantiate module");
3168 auto ¬e = diag.attachNote();
3169 note <<
"missing layer requirements: ";
3170 interleaveComma(missingLayers, note);
3175InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3176 auto caseNames = getCaseNamesAttr();
3177 for (
auto moduleName : getModuleNamesAttr()) {
3178 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3184 auto referencedModule =
3185 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3186 if (isa<FIntModuleOp>(referencedModule))
3187 return emitOpError(
"intmodule must be instantiated with instance op, "
3188 "not via 'firrtl.instance_choice'");
3191 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3192 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3193 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3194 auto refRoot = ref.getRootReference();
3195 if (ref.getRootReference() != root)
3196 return emitOpError() <<
"case " << ref
3197 <<
" is not in the same option group as "
3200 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3201 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3203 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3204 return emitOpError() <<
"option " << refRoot
3205 <<
" does not contain option case " << ref;
3212InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3213 auto caseNames = getCaseNamesAttr();
3214 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3215 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3216 if (caseSym == option.getSymName())
3217 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3219 return getDefaultTargetAttr();
3222SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3223InstanceChoiceOp::getTargetChoices() {
3224 auto caseNames = getCaseNamesAttr();
3225 auto moduleNames = getModuleNamesAttr();
3226 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3227 for (
size_t i = 0; i < caseNames.size(); ++i) {
3228 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3229 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3235InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPorts(
3236 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3240 auto oldPortCount = getNumResults();
3241 auto numInsertions = insertions.size();
3242 auto newPortCount = oldPortCount + numInsertions;
3244 SmallVector<Direction> newPortDirections;
3245 SmallVector<Attribute> newPortNames;
3246 SmallVector<Type> newPortTypes;
3247 SmallVector<Attribute> newPortAnnos;
3248 SmallVector<Attribute> newDomainInfo;
3250 newPortDirections.reserve(newPortCount);
3251 newPortNames.reserve(newPortCount);
3252 newPortTypes.reserve(newPortCount);
3253 newPortAnnos.reserve(newPortCount);
3254 newDomainInfo.reserve(newPortCount);
3256 SmallVector<unsigned> indexMap(oldPortCount);
3258 size_t inserted = 0;
3259 for (
size_t i = 0; i < oldPortCount; ++i) {
3260 while (inserted < numInsertions) {
3261 auto &[index,
info] = insertions[inserted];
3267 newPortDirections.push_back(
info.direction);
3268 newPortNames.push_back(
info.name);
3269 newPortTypes.push_back(
info.type);
3270 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3271 newDomainInfo.push_back(domains);
3275 newPortDirections.push_back(getPortDirection(i));
3276 newPortNames.push_back(getPortNameAttr(i));
3277 newPortTypes.push_back(getType(i));
3278 newPortAnnos.push_back(getPortAnnotations()[i]);
3279 newDomainInfo.push_back(getDomainInfo()[i]);
3280 indexMap[i] = i + inserted;
3283 while (inserted < numInsertions) {
3284 auto &[index,
info] = insertions[inserted];
3287 newPortDirections.push_back(
info.direction);
3288 newPortNames.push_back(
info.name);
3289 newPortTypes.push_back(
info.type);
3290 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3291 newDomainInfo.push_back(domains);
3295 OpBuilder builder(*
this);
3296 auto clone = InstanceChoiceOp::create(
3297 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3300 ArrayAttr::get(
context, newPortNames),
3301 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3302 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr());
3304 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3305 clone->setAttr(
"output_file", outputFile);
3310InstanceChoiceOp InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3311 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3312 auto clone = cloneWithInsertedPorts(insertions);
3318InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3319 assert(erasures.size() >= getNumResults() &&
3320 "erasures is not at least as large as getNumResults()");
3322 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3323 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3324 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3326 SmallVector<Attribute> newPortNames =
3328 SmallVector<Attribute> newPortAnnotations =
3330 ArrayAttr newPortDomains =
3334 OpBuilder builder(*
this);
3335 auto clone = InstanceChoiceOp::create(
3336 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3339 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3340 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3341 getLayers(), getInnerSymAttr());
3343 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3344 clone->setAttr(
"output_file", outputFile);
3349InstanceChoiceOp InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3350 const llvm::BitVector &erasures) {
3351 auto clone = cloneWithErasedPorts(erasures);
3360ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3361 assert(portIdx < getNumResults() &&
3362 "index should be smaller than result number");
3363 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3366void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3367 assert(annotations.size() == getNumResults() &&
3368 "number of annotations is not equal to result number");
3369 (*this)->setAttr(
"portAnnotations",
3370 ArrayAttr::get(getContext(), annotations));
3374void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3375 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3378 numReadWritePorts = 0;
3380 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3381 auto portKind = getPortKind(i);
3382 if (portKind == MemOp::PortKind::Debug)
3384 else if (portKind == MemOp::PortKind::Read)
3386 else if (portKind == MemOp::PortKind::Write) {
3389 ++numReadWritePorts;
3394LogicalResult MemOp::verify() {
3398 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3404 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3405 auto portName = getPortNameAttr(i);
3410 BundleType portBundleType =
3411 type_dyn_cast<BundleType>(getResult(i).getType());
3414 if (!portNamesSet.insert(portName).second) {
3415 emitOpError() <<
"has non-unique port name " << portName;
3423 auto elt = getPortNamed(portName);
3425 emitOpError() <<
"could not get port with name " << portName;
3428 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3431 if (portKind == MemOp::PortKind::Debug &&
3432 !type_isa<RefType>(getResult(i).getType()))
3433 return emitOpError() <<
"has an invalid type on port " << portName
3434 <<
" (expected Read/Write/ReadWrite/Debug)";
3435 if (type_isa<RefType>(firrtlType) && e == 1)
3436 return emitOpError()
3437 <<
"cannot have only one port of debug type. Debug port can only "
3438 "exist alongside other read/write/read-write port";
3443 if (portKind == MemOp::PortKind::Debug) {
3444 auto resType = type_cast<RefType>(getResult(i).getType());
3445 if (!(resType && type_isa<FVectorType>(resType.getType())))
3446 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3447 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3449 auto dataTypeOption = portBundleType.getElement(
"data");
3450 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3451 dataTypeOption = portBundleType.getElement(
"wdata");
3452 if (!dataTypeOption) {
3453 emitOpError() <<
"has no data field on port " << portName
3454 <<
" (expected to see \"data\" for a read or write "
3455 "port or \"rdata\" for a read/write port)";
3458 dataType = dataTypeOption->type;
3460 if (portKind == MemOp::PortKind::Read) {
3467 emitOpError() <<
"has non-passive data type on port " << portName
3468 <<
" (memory types must be passive)";
3473 if (dataType.containsAnalog()) {
3474 emitOpError() <<
"has a data type that contains an analog type on port "
3476 <<
" (memory types cannot contain analog types)";
3484 getTypeForPort(getDepth(), dataType, portKind,
3485 dataType.isGround() ? getMaskBits() : 0);
3488 auto originalType = getResult(i).getType();
3489 if (originalType != expectedType) {
3490 StringRef portKindName;
3492 case MemOp::PortKind::Read:
3493 portKindName =
"read";
3495 case MemOp::PortKind::Write:
3496 portKindName =
"write";
3498 case MemOp::PortKind::ReadWrite:
3499 portKindName =
"readwrite";
3501 case MemOp::PortKind::Debug:
3502 portKindName =
"dbg";
3505 emitOpError() <<
"has an invalid type for port " << portName
3506 <<
" of determined kind \"" << portKindName
3507 <<
"\" (expected " << expectedType <<
", but got "
3508 << originalType <<
")";
3514 if (oldDataType && oldDataType != dataType) {
3515 emitOpError() <<
"port " << getPortNameAttr(i)
3516 <<
" has a different type than port "
3517 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3518 <<
", but got " << dataType <<
")";
3522 oldDataType = dataType;
3525 auto maskWidth = getMaskBits();
3527 auto dataWidth = getDataType().getBitWidthOrSentinel();
3528 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3529 return emitOpError(
"the mask width cannot be greater than "
3532 if (getPortAnnotations().size() != getNumResults())
3533 return emitOpError(
"the number of result annotations should be "
3534 "equal to the number of results");
3540 return std::max(1U, llvm::Log2_64_Ceil(depth));
3546 PortKind portKind,
size_t maskBits) {
3548 auto *
context = dataType.getContext();
3549 if (portKind == PortKind::Debug)
3550 return RefType::get(FVectorType::get(dataType, depth));
3556 maskType = UIntType::get(
context, maskBits);
3558 auto getId = [&](StringRef name) -> StringAttr {
3559 return StringAttr::get(
context, name);
3562 SmallVector<BundleType::BundleElement, 7> portFields;
3566 portFields.push_back({getId(
"addr"),
false, addressType});
3567 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3568 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3571 case PortKind::Read:
3572 portFields.push_back({getId(
"data"),
true, dataType});
3575 case PortKind::Write:
3576 portFields.push_back({getId(
"data"),
false, dataType});
3577 portFields.push_back({getId(
"mask"),
false, maskType});
3580 case PortKind::ReadWrite:
3581 portFields.push_back({getId(
"rdata"),
true, dataType});
3582 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3583 portFields.push_back({getId(
"wdata"),
false, dataType});
3584 portFields.push_back({getId(
"wmask"),
false, maskType});
3587 llvm::report_fatal_error(
"memory port kind not handled");
3591 return BundleType::get(
context, portFields);
3595SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3596 SmallVector<MemOp::NamedPort> result;
3598 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3600 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3607MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3609 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3613MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3615 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3619size_t MemOp::getMaskBits() {
3621 for (
auto res : getResults()) {
3622 if (type_isa<RefType>(res.getType()))
3624 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3631 if (t.name.getValue().contains(
"mask"))
3634 if (type_isa<UIntType>(mType))
3644 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3646 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3647 return type_cast<FVectorType>(refType.getType()).getElementType();
3648 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3650 StringRef dataFieldName =
"data";
3652 dataFieldName =
"rdata";
3654 return type_cast<BundleType>(firstPortType.getPassiveType())
3655 .getElementType(dataFieldName);
3658StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3659 return cast<StringAttr>(getPortNames()[resultNo]);
3663 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3666Value MemOp::getPortNamed(StringAttr name) {
3667 auto namesArray = getPortNames();
3668 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3669 if (namesArray[i] == name) {
3670 assert(i < getNumResults() &&
" names array out of sync with results");
3671 return getResult(i);
3680 size_t numReadPorts = 0;
3681 size_t numWritePorts = 0;
3682 size_t numReadWritePorts = 0;
3684 SmallVector<int32_t> writeClockIDs;
3686 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3687 auto portKind = op.getPortKind(i);
3688 if (portKind == MemOp::PortKind::Read)
3690 else if (portKind == MemOp::PortKind::Write) {
3691 for (
auto *a : op.getResult(i).getUsers()) {
3692 auto subfield = dyn_cast<SubfieldOp>(a);
3693 if (!subfield || subfield.getFieldIndex() != 2)
3695 auto clockPort = a->getResult(0);
3696 for (
auto *b : clockPort.getUsers()) {
3697 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3698 if (
connect.getDest() == clockPort) {
3701 connect.getSrc(),
true,
true,
true),
3703 if (result.second) {
3704 writeClockIDs.push_back(numWritePorts);
3706 writeClockIDs.push_back(result.first->second);
3715 ++numReadWritePorts;
3722 op.emitError(
"'firrtl.mem' should have simple type and known width");
3723 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3725 if (op->hasAttr(
"modName"))
3726 modName = op->getAttrOfType<StringAttr>(
"modName");
3728 SmallString<8> clocks;
3729 for (
auto a : writeClockIDs)
3730 clocks.
append(Twine((char)(a +
'a')).str());
3731 SmallString<32> initStr;
3736 for (
auto c : init.getFilename().getValue())
3737 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3738 (c >=
'0' && c <=
'9'))
3739 initStr.push_back(c);
3740 initStr.push_back(
'_');
3741 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3742 initStr.push_back(
'_');
3743 initStr.push_back(init.getIsInline() ?
't' :
'f');
3745 modName = StringAttr::get(
3748 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3749 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3750 numReadWritePorts, (
size_t)width, op.getDepth(),
3751 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3752 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3753 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3755 return {numReadPorts,
3760 op.getReadLatency(),
3761 op.getWriteLatency(),
3763 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3764 seq::WUW::PortOrder,
3767 op.getMaskBits() > 1,
3773void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3778 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3779 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3783std::optional<size_t> MemOp::getTargetResultIndex() {
3785 return std::nullopt;
3793 OpAsmSetValueNameFn setNameFn) {
3796 setNameFn(op.getDataRaw(), name);
3797 if (op.isForceable())
3798 setNameFn(op.getDataRef(), (name +
"_ref").str());
3801void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3805LogicalResult NodeOp::inferReturnTypes(
3806 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3807 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3808 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3809 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3810 if (operands.empty())
3812 Adaptor adaptor(operands, attributes, properties, regions);
3813 inferredReturnTypes.push_back(adaptor.getInput().getType());
3814 if (adaptor.getForceable()) {
3816 true, adaptor.getInput().getType());
3817 if (!forceableType) {
3819 ::mlir::emitError(*location,
"cannot force a node of type ")
3820 << operands[0].getType();
3823 inferredReturnTypes.push_back(forceableType);
3828std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3830void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3834std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3836SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3837RegOp::computeDataFlow() {
3842LogicalResult RegResetOp::verify() {
3843 auto reset = getResetValue();
3850 return emitError(
"type mismatch between register ")
3851 << regType <<
" and reset value " << resetType;
3856std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3858void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3867FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3868 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3870 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3872 if (!isa<FModuleLike>(op)) {
3873 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3874 <<
" is not a module";
3875 d.attachNote(op->getLoc()) <<
"target defined here";
3887SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3888 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3890 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3892 auto complain = [&] {
3893 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3894 d.attachNote(op->getLoc()) <<
"target defined here";
3898 auto module = dyn_cast<FModuleLike>(op);
3900 return complain() <<
"is not a module";
3902 auto numPorts =
module.getNumPorts();
3904 return complain() <<
"must have at least 4 ports, got " << numPorts
3908 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3909 llvm::function_ref<bool(Type)> checkType,
3910 StringRef expType) {
3911 auto name =
module.getPortNameAttr(idx);
3912 if (name != expName) {
3913 complain() <<
"port " << idx <<
" must be called \"" << expName
3914 <<
"\", got " << name <<
" instead";
3917 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3921 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3922 <<
", got " << stringify(dir) <<
" instead";
3925 if (
auto type = module.getPortType(idx); !checkType(type)) {
3926 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3927 <<
"', got " << type <<
" instead";
3933 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3934 auto isBool = [](Type type) {
3935 if (
auto uintType = dyn_cast<UIntType>(type))
3936 return uintType.getWidth() == 1;
3940 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3947 for (
unsigned i = 4; i < numPorts; ++i) {
3948 auto type =
module.getPortType(i);
3949 if (!isa<PropertyType>(type))
3950 return complain() <<
"port " << i <<
" may only be a property type, got "
3951 << type <<
" instead";
3961void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3965SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3966RegResetOp::computeDataFlow() {
3971std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3973LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3974 auto refType = type_dyn_cast<RefType>(getType(0));
3979 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3980 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3987LogicalResult ContractOp::verify() {
3988 if (getBody().getArgumentTypes() != getInputs().getType())
3989 return emitOpError(
"result types and region argument types must match");
3997void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3999 build(builder, state, klass.getInstanceType(),
4000 StringAttr::get(builder.getContext(), name));
4003LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4004 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4005 auto classType = getType();
4006 auto className = classType.getNameAttr();
4009 auto classOp = dyn_cast_or_null<ClassLike>(
4010 symbolTable.lookupSymbolIn(circuitOp, className));
4012 return emitOpError() <<
"references unknown class " << className;
4015 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4021StringAttr ObjectOp::getClassNameAttr() {
4022 return getType().getNameAttr().getAttr();
4025StringRef ObjectOp::getClassName() {
return getType().getName(); }
4027ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4028 auto symRef = getType().getNameAttr();
4029 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4032Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4033 return getReferencedClass(symtbl);
4036StringRef ObjectOp::getInstanceName() {
return getName(); }
4038StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4040StringAttr ObjectOp::getReferencedModuleNameAttr() {
4041 return getClassNameAttr();
4044void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4045 setNameFn(getResult(),
getName());
4052LogicalResult AttachOp::verify() {
4054 std::optional<int32_t> commonWidth;
4055 for (
auto operand : getOperands()) {
4056 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4060 commonWidth = thisWidth;
4063 if (commonWidth != thisWidth)
4064 return emitOpError(
"is inavlid as not all known operand widths match");
4071 Value dst = connect->getOperand(0);
4072 Value src = connect->getOperand(1);
4081 if (isa<PropertyType>(src.getType()) ||
4085 auto diag = emitError(connect->getLoc());
4086 diag <<
"connect has invalid flow: the source expression ";
4088 diag <<
"\"" << srcName <<
"\" ";
4089 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4090 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4098 auto diag = emitError(connect->getLoc());
4099 diag <<
"connect has invalid flow: the destination expression ";
4101 diag <<
"\"" << dstName <<
"\" ";
4102 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4103 return diag.attachNote(dstRef.getLoc())
4104 <<
"the destination was defined here";
4113 bool outerTypeIsConst =
false) {
4114 auto typeIsConst = outerTypeIsConst || type.
isConst();
4119 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4120 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4121 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4125 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4137 auto dest = connect.getDest();
4138 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4139 auto src = connect.getSrc();
4140 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4141 if (!destType || !srcType)
4144 auto destRefinedType = destType;
4145 auto srcRefinedType = srcType;
4150 auto findFieldDeclarationRefiningFieldType =
4152 while (
auto *definingOp = value.getDefiningOp()) {
4153 bool shouldContinue =
true;
4154 TypeSwitch<Operation *>(definingOp)
4155 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4156 .Case<SubaccessOp>([&](SubaccessOp op) {
4160 .getElementTypePreservingConst()
4162 originalFieldType = originalFieldType.getConstType(
true);
4163 value = op.getInput();
4165 .Default([&](Operation *) { shouldContinue =
false; });
4166 if (!shouldContinue)
4172 auto destDeclaration =
4173 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4174 auto srcDeclaration =
4175 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4177 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4178 Value declaration) -> LogicalResult {
4179 auto *declarationBlock = declaration.getParentBlock();
4180 auto *block = connect->getBlock();
4181 while (block && block != declarationBlock) {
4182 auto *parentOp = block->getParentOp();
4184 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4185 whenOp && !whenOp.getCondition().getType().isConst()) {
4187 return connect.emitOpError()
4188 <<
"assignment to 'const' type " << type
4189 <<
" is dependent on a non-'const' condition";
4190 return connect->emitOpError()
4191 <<
"assignment to nested 'const' member of type " << type
4192 <<
" is dependent on a non-'const' condition";
4195 block = parentOp->getBlock();
4200 auto emitSubaccessError = [&] {
4201 return connect.emitError(
4202 "assignment to non-'const' subaccess of 'const' type is disallowed");
4208 if (destType != destRefinedType)
4209 return emitSubaccessError();
4211 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4216 if (srcRefinedType.containsConst() &&
4219 if (srcType != srcRefinedType)
4220 return emitSubaccessError();
4221 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4238 auto dest = connect.getDest();
4239 for (
auto *user : dest.getUsers()) {
4240 if (
auto c = dyn_cast<FConnectLike>(user);
4241 c && c.getDest() == dest && c != connect) {
4242 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4244 diag.attachNote(c->getLoc()) <<
"other driver is here";
4251LogicalResult ConnectOp::verify() {
4252 auto dstType = getDest().getType();
4253 auto srcType = getSrc().getType();
4254 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4255 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4256 if (!dstBaseType || !srcBaseType) {
4257 if (dstType != srcType)
4258 return emitError(
"may not connect different non-base types");
4261 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4262 return emitError(
"analog types may not be connected");
4266 return emitError(
"type mismatch between destination ")
4267 << dstBaseType <<
" and source " << srcBaseType;
4272 return emitError(
"destination ")
4273 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4286LogicalResult MatchingConnectOp::verify() {
4287 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4288 auto baseType = type_cast<FIRRTLBaseType>(type);
4291 if (baseType && baseType.containsAnalog())
4292 return emitError(
"analog types may not be connected");
4297 "`SameAnonTypeOperands` trait should have already rejected "
4298 "structurally non-equivalent types");
4311LogicalResult RefDefineOp::verify() {
4318 if (
auto *op = getDest().getDefiningOp()) {
4320 if (isa<RefSubOp>(op))
4322 "destination reference cannot be a sub-element of a reference");
4323 if (isa<RefCastOp>(op))
4325 "destination reference cannot be a cast of another reference");
4333 SmallVector<SymbolRefAttr> missingLayers;
4336 "has more layer requirements than destination",
4337 "additional layers required");
4340LogicalResult PropAssignOp::verify() {
4350template <
typename T>
4352 auto info = op.getDomainInfo();
4355 return dyn_cast<FlatSymbolRefAttr>(info[i]);
4359 if (!isa<DomainType>(value.getType()))
4362 if (
auto arg = dyn_cast<BlockArgument>(value)) {
4363 auto *parent = arg.getOwner()->getParentOp();
4364 if (
auto module = dyn_cast<FModuleLike>(parent)) {
4365 auto info =
module.getDomainInfo();
4368 auto attr = info[arg.getArgNumber()];
4369 return dyn_cast<FlatSymbolRefAttr>(attr);
4375 if (
auto result = dyn_cast<OpResult>(value)) {
4376 auto *op = result.getDefiningOp();
4377 if (
auto instance = dyn_cast<InstanceOp>(op))
4379 if (
auto instance = dyn_cast<InstanceChoiceOp>(op))
4381 if (
auto anonDomain = dyn_cast<DomainCreateAnonOp>(op))
4382 return anonDomain.getDomainAttr();
4389LogicalResult DomainDefineOp::verify() {
4396 auto dst = getDest();
4397 auto src = getSrc();
4405 if (
auto *srcDefOp = src.getDefiningOp())
4406 if (isa<WireOp>(srcDefOp))
4408 if (
auto *dstDefOp = dst.getDefiningOp())
4409 if (isa<WireOp>(dstDefOp))
4414 return emitError(
"could not determine domain-type of destination");
4418 return emitError(
"could not determine domain-type of source");
4420 if (dstDomain != srcDomain) {
4421 auto diag = emitError()
4422 <<
"source domain type " << srcDomain
4423 <<
" does not match destination domain type " << dstDomain;
4430void WhenOp::createElseRegion() {
4431 assert(!hasElseRegion() &&
"already has an else region");
4432 getElseRegion().push_back(
new Block());
4435void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4436 bool withElseRegion, std::function<
void()> thenCtor,
4437 std::function<
void()> elseCtor) {
4438 OpBuilder::InsertionGuard guard(builder);
4439 result.addOperands(condition);
4442 builder.createBlock(result.addRegion());
4447 Region *elseRegion = result.addRegion();
4448 if (withElseRegion) {
4449 builder.createBlock(elseRegion);
4459LogicalResult MatchOp::verify() {
4460 FEnumType type = getInput().getType();
4463 auto numCases = getTags().size();
4464 auto numRegions = getNumRegions();
4465 if (numRegions != numCases)
4466 return emitOpError(
"expected ")
4467 << numRegions <<
" tags but got " << numCases;
4469 auto numTags = type.getNumElements();
4471 SmallDenseSet<int64_t> seen;
4472 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4473 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4476 if (region.getNumArguments() != 1)
4477 return emitOpError(
"region should have exactly one argument");
4480 if (tagIndex >= numTags)
4481 return emitOpError(
"the tag index ")
4482 << tagIndex <<
" is out of the range of valid tags in " << type;
4485 auto [it, inserted] = seen.insert(tagIndex);
4487 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4488 <<
" is matched more than once";
4491 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4492 auto regionType = region.getArgument(0).getType();
4493 if (regionType != expectedType)
4494 return emitOpError(
"region type ")
4495 << regionType <<
" does not match the expected type "
4500 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4501 if (!seen.contains(i))
4502 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4507void MatchOp::print(OpAsmPrinter &p) {
4508 auto input = getInput();
4509 FEnumType type = input.getType();
4510 auto regions = getRegions();
4511 p <<
" " << input <<
" : " << type;
4512 SmallVector<StringRef> elided = {
"tags"};
4513 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4516 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4519 p.printKeywordOrString(
4520 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4522 p.printRegionArgument(region.front().getArgument(0), {},
4525 p.printRegion(region,
false);
4532ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4533 auto *
context = parser.getContext();
4534 auto &properties = result.getOrAddProperties<Properties>();
4535 OpAsmParser::UnresolvedOperand input;
4536 if (parser.parseOperand(input) || parser.parseColon())
4539 auto loc = parser.getCurrentLocation();
4541 if (parser.parseType(type))
4543 auto enumType = type_dyn_cast<FEnumType>(type);
4545 return parser.emitError(loc,
"expected enumeration type but got") << type;
4547 if (parser.resolveOperand(input, type, result.operands) ||
4548 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4549 parser.parseLBrace())
4552 auto i32Type = IntegerType::get(
context, 32);
4553 SmallVector<Attribute> tags;
4556 if (failed(parser.parseOptionalKeyword(
"case")))
4560 auto nameLoc = parser.getCurrentLocation();
4562 OpAsmParser::Argument arg;
4563 auto *region = result.addRegion();
4564 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4565 parser.parseArgument(arg) || parser.parseRParen())
4569 auto index = enumType.getElementIndex(name);
4571 return parser.emitError(nameLoc,
"the tag \"")
4572 << name <<
"\" is not a member of the enumeration " << enumType;
4573 tags.push_back(IntegerAttr::get(i32Type, *index));
4576 arg.type = enumType.getElementTypePreservingConst(*index);
4577 if (parser.parseRegion(*region, arg))
4580 properties.setTags(ArrayAttr::get(
context, tags));
4582 return parser.parseRBrace();
4585void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4587 MutableArrayRef<std::unique_ptr<Region>> regions) {
4588 auto &properties = result.getOrAddProperties<Properties>();
4589 result.addOperands(input);
4590 properties.setTags(tags);
4591 result.addRegions(regions);
4600 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4601 bool visitInvalidExpr(Operation *op) {
return false; }
4602 bool visitUnhandledExpr(Operation *op) {
return true; }
4608void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4611 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4612 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4613 auto width = ty.getWidthOrSentinel();
4617 name = (Twine(base) + Twine(width)).str();
4618 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4619 auto width = ty.getWidthOrSentinel();
4621 name =
"invalid_analog";
4623 name = (
"invalid_analog" + Twine(width)).str();
4624 }
else if (type_isa<AsyncResetType>(getType()))
4625 name =
"invalid_asyncreset";
4626 else if (type_isa<ResetType>(getType()))
4627 name =
"invalid_reset";
4628 else if (type_isa<ClockType>(getType()))
4629 name =
"invalid_clock";
4633 setNameFn(getResult(), name);
4636void ConstantOp::print(OpAsmPrinter &p) {
4638 p.printAttributeWithoutType(getValueAttr());
4640 p.printType(getType());
4641 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4644ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4645 auto &properties = result.getOrAddProperties<Properties>();
4648 auto loc = parser.getCurrentLocation();
4649 auto valueResult = parser.parseOptionalInteger(value);
4650 if (!valueResult.has_value())
4651 return parser.emitError(loc,
"expected integer value");
4655 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4656 parser.parseOptionalAttrDict(result.attributes))
4658 result.addTypes(resultType);
4664 if (width > value.getBitWidth()) {
4668 value = value.sext(width);
4669 }
else if (width < value.getBitWidth()) {
4672 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4673 : value.getActiveBits();
4674 if (width < neededBits)
4675 return parser.emitError(loc,
"constant out of range for result type ")
4677 value = value.trunc(width);
4681 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4683 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4684 properties.setValue(valueAttr);
4688LogicalResult ConstantOp::verify() {
4692 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4694 "firrtl.constant attribute bitwidth doesn't match return type");
4697 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4698 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4699 return emitError(
"firrtl.constant attribute has wrong sign");
4706void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4707 const APInt &value) {
4710 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4711 "incorrect attribute bitwidth for firrtl.constant");
4714 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4715 return build(builder, result, type, attr);
4720void ConstantOp::build(OpBuilder &builder, OperationState &result,
4721 const APSInt &value) {
4722 auto attr = IntegerAttr::get(builder.getContext(), value);
4724 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4725 return build(builder, result, type, attr);
4728void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4735 SmallString<32> specialNameBuffer;
4736 llvm::raw_svector_ostream specialName(specialNameBuffer);
4738 getValue().print(specialName, intTy.
isSigned());
4740 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4743 specialName << width;
4744 setNameFn(getResult(), specialName.str());
4747void SpecialConstantOp::print(OpAsmPrinter &p) {
4750 p << static_cast<unsigned>(getValue());
4752 p.printType(getType());
4753 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4756ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4757 OperationState &result) {
4758 auto &properties = result.getOrAddProperties<Properties>();
4762 auto loc = parser.getCurrentLocation();
4763 auto valueResult = parser.parseOptionalInteger(value);
4764 if (!valueResult.has_value())
4765 return parser.emitError(loc,
"expected integer value");
4768 if (value != 0 && value != 1)
4769 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4773 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4774 parser.parseOptionalAttrDict(result.attributes))
4776 result.addTypes(resultType);
4779 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4780 properties.setValue(valueAttr);
4784void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4785 SmallString<32> specialNameBuffer;
4786 llvm::raw_svector_ostream specialName(specialNameBuffer);
4788 specialName << static_cast<unsigned>(getValue());
4789 auto type = getType();
4790 if (type_isa<ClockType>(type)) {
4791 specialName <<
"_clock";
4792 }
else if (type_isa<ResetType>(type)) {
4793 specialName <<
"_reset";
4794 }
else if (type_isa<AsyncResetType>(type)) {
4795 specialName <<
"_asyncreset";
4797 setNameFn(getResult(), specialName.str());
4804 if (type.isGround()) {
4805 if (!isa<IntegerAttr>(attr)) {
4806 op->emitOpError(
"Ground type is not an integer attribute");
4811 auto attrlist = dyn_cast<ArrayAttr>(attr);
4813 op->emitOpError(
"expected array attribute for aggregate constant");
4816 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4817 if (array.getNumElements() != attrlist.size()) {
4818 op->emitOpError(
"array attribute (")
4819 << attrlist.size() <<
") has wrong size for vector constant ("
4820 << array.getNumElements() <<
")";
4823 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4827 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4828 if (bundle.getNumElements() != attrlist.size()) {
4829 op->emitOpError(
"array attribute (")
4830 << attrlist.size() <<
") has wrong size for bundle constant ("
4831 << bundle.getNumElements() <<
")";
4834 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4835 if (bundle.getElement(i).isFlip) {
4836 op->emitOpError(
"Cannot have constant bundle type with flip");
4844 op->emitOpError(
"Unknown aggregate type");
4848LogicalResult AggregateConstantOp::verify() {
4854Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4856 Attribute value = getFields();
4857 while (fieldID != 0) {
4858 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4859 auto index = bundle.getIndexForFieldID(fieldID);
4860 fieldID -= bundle.getFieldID(index);
4861 type = bundle.getElementType(index);
4862 value = cast<ArrayAttr>(value)[index];
4864 auto vector = type_cast<FVectorType>(type);
4865 auto index = vector.getIndexForFieldID(fieldID);
4866 fieldID -= vector.getFieldID(index);
4867 type = vector.getElementType();
4868 value = cast<ArrayAttr>(value)[index];
4874LogicalResult FIntegerConstantOp::verify() {
4875 auto i = getValueAttr();
4876 if (!i.getType().isSignedInteger())
4877 return emitOpError(
"value must be signed");
4881void FIntegerConstantOp::print(OpAsmPrinter &p) {
4883 p.printAttributeWithoutType(getValueAttr());
4884 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4887ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4888 OperationState &result) {
4889 auto *
context = parser.getContext();
4890 auto &properties = result.getOrAddProperties<Properties>();
4892 if (parser.parseInteger(value) ||
4893 parser.parseOptionalAttrDict(result.attributes))
4895 result.addTypes(FIntegerType::get(
context));
4897 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4898 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4899 properties.setValue(valueAttr);
4903ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4904 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4907 if (parser.parseOperandList(operands) ||
4908 parser.parseOptionalAttrDict(result.attributes) ||
4909 parser.parseColonType(type))
4911 result.addTypes(type);
4913 return parser.resolveOperands(operands, type.getElementType(),
4917void ListCreateOp::print(OpAsmPrinter &p) {
4919 p.printOperands(getElements());
4920 p.printOptionalAttrDict((*this)->getAttrs());
4921 p <<
" : " << getType();
4924LogicalResult ListCreateOp::verify() {
4925 if (getElements().
empty())
4928 auto elementType = getElements().front().getType();
4929 auto listElementType = getType().getElementType();
4931 return emitOpError(
"has elements of type ")
4932 <<
elementType <<
" instead of " << listElementType;
4937LogicalResult BundleCreateOp::verify() {
4938 BundleType resultType = getType();
4939 if (resultType.getNumElements() != getFields().size())
4940 return emitOpError(
"number of fields doesn't match type");
4941 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4943 resultType.getElementTypePreservingConst(i),
4944 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4945 return emitOpError(
"type of element doesn't match bundle for field ")
4946 << resultType.getElement(i).name;
4951LogicalResult VectorCreateOp::verify() {
4952 FVectorType resultType = getType();
4953 if (resultType.getNumElements() != getFields().size())
4954 return emitOpError(
"number of fields doesn't match type");
4955 auto elemTy = resultType.getElementTypePreservingConst();
4956 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4958 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4959 return emitOpError(
"type of element doesn't match vector element");
4965UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4967 auto classType = dyn_cast<ClassType>(getType());
4971 auto className = classType.getNameAttr();
4973 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
4975 return emitOpError() <<
"refers to non-existent class ("
4976 << className.getAttr() <<
")";
4979 if (!isa<ClassLike>(op))
4980 return emitOpError() <<
"refers to a non-class type ("
4981 << className.getAttr() <<
")";
4990LogicalResult FEnumCreateOp::verify() {
4991 FEnumType resultType = getResult().getType();
4992 auto elementIndex = resultType.getElementIndex(
getFieldName());
4994 return emitOpError(
"label ")
4995 <<
getFieldName() <<
" is not a member of the enumeration type "
4998 resultType.getElementTypePreservingConst(*elementIndex),
4999 getInput().getType()))
5000 return emitOpError(
"type of element doesn't match enum element");
5004void FEnumCreateOp::print(OpAsmPrinter &printer) {
5007 printer <<
'(' << getInput() <<
')';
5008 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5009 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5011 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5012 ArrayRef<Type>{getResult().getType()});
5015ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5016 auto *
context = parser.getContext();
5017 auto &properties = result.getOrAddProperties<Properties>();
5019 OpAsmParser::UnresolvedOperand input;
5020 std::string fieldName;
5021 mlir::FunctionType functionType;
5022 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5023 parser.parseOperand(input) || parser.parseRParen() ||
5024 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5025 parser.parseType(functionType))
5028 if (functionType.getNumInputs() != 1)
5029 return parser.emitError(parser.getNameLoc(),
"single input type required");
5030 if (functionType.getNumResults() != 1)
5031 return parser.emitError(parser.getNameLoc(),
"single result type required");
5033 auto inputType = functionType.getInput(0);
5034 if (parser.resolveOperand(input, inputType, result.operands))
5037 auto outputType = functionType.getResult(0);
5038 auto enumType = type_dyn_cast<FEnumType>(outputType);
5040 return parser.emitError(parser.getNameLoc(),
5041 "output must be enum type, got ")
5043 auto fieldIndex = enumType.getElementIndex(fieldName);
5045 return parser.emitError(parser.getNameLoc(),
5046 "unknown field " + fieldName +
" in enum type ")
5049 properties.setFieldIndex(
5050 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5052 result.addTypes(enumType);
5061LogicalResult IsTagOp::verify() {
5062 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5063 return emitOpError(
"element index is greater than the number of fields in "
5068void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5069 printer <<
' ' << getInput() <<
' ';
5071 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5072 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5073 printer <<
" : " << getInput().getType();
5076ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5077 auto *
context = parser.getContext();
5078 auto &properties = result.getOrAddProperties<Properties>();
5080 OpAsmParser::UnresolvedOperand input;
5081 std::string fieldName;
5083 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5084 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5085 parser.parseType(inputType))
5088 if (parser.resolveOperand(input, inputType, result.operands))
5091 auto enumType = type_dyn_cast<FEnumType>(inputType);
5093 return parser.emitError(parser.getNameLoc(),
5094 "input must be enum type, got ")
5096 auto fieldIndex = enumType.getElementIndex(fieldName);
5098 return parser.emitError(parser.getNameLoc(),
5099 "unknown field " + fieldName +
" in enum type ")
5102 properties.setFieldIndex(
5103 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5105 result.addTypes(UIntType::get(
context, 1,
false));
5110FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5111 OpaqueProperties properties,
5112 mlir::RegionRange regions,
5113 std::optional<Location> loc) {
5114 Adaptor adaptor(operands, attrs, properties, regions);
5115 return UIntType::get(attrs.getContext(), 1,
5116 isConst(adaptor.getInput().getType()));
5119template <
typename OpTy>
5121 auto *
context = parser.getContext();
5123 OpAsmParser::UnresolvedOperand input;
5124 std::string fieldName;
5126 if (parser.parseOperand(input) || parser.parseLSquare() ||
5127 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5128 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5129 parser.parseType(inputType))
5132 if (parser.resolveOperand(input, inputType, result.operands))
5135 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5137 return parser.emitError(parser.getNameLoc(),
5138 "input must be bundle type, got ")
5140 auto fieldIndex = bundleType.getElementIndex(fieldName);
5142 return parser.emitError(parser.getNameLoc(),
5143 "unknown field " + fieldName +
" in bundle type ")
5146 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5147 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5149 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5152 result.addTypes(type);
5157ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5158 auto *
context = parser.getContext();
5160 OpAsmParser::UnresolvedOperand input;
5161 std::string fieldName;
5163 if (parser.parseOperand(input) || parser.parseLSquare() ||
5164 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5165 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5166 parser.parseType(inputType))
5169 if (parser.resolveOperand(input, inputType, result.operands))
5172 auto enumType = type_dyn_cast<FEnumType>(inputType);
5174 return parser.emitError(parser.getNameLoc(),
5175 "input must be enum type, got ")
5177 auto fieldIndex = enumType.getElementIndex(fieldName);
5179 return parser.emitError(parser.getNameLoc(),
5180 "unknown field " + fieldName +
" in enum type ")
5183 result.getOrAddProperties<Properties>().setFieldIndex(
5184 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5186 SmallVector<Type> inferredReturnTypes;
5187 if (failed(SubtagOp::inferReturnTypes(
5188 context, result.location, result.operands,
5189 result.attributes.getDictionary(
context), result.getRawProperties(),
5190 result.regions, inferredReturnTypes)))
5192 result.addTypes(inferredReturnTypes);
5197ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5198 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5200ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5201 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5204template <
typename OpTy>
5206 printer <<
' ' << op.getInput() <<
'[';
5207 printer.printKeywordOrString(op.getFieldName());
5209 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5210 elidedAttrs.push_back(
"fieldIndex");
5211 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5212 printer <<
" : " << op.getInput().getType();
5214void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5215 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5217void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5218 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5221void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5222 printer <<
' ' << getInput() <<
'[';
5225 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5226 elidedAttrs.push_back(
"fieldIndex");
5227 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5228 printer <<
" : " << getInput().getType();
5231template <
typename OpTy>
5233 if (op.getFieldIndex() >=
5234 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5236 return op.emitOpError(
"subfield element index is greater than the number "
5237 "of fields in the bundle type");
5240LogicalResult SubfieldOp::verify() {
5241 return verifySubfieldLike<SubfieldOp>(*
this);
5243LogicalResult OpenSubfieldOp::verify() {
5244 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5247LogicalResult SubtagOp::verify() {
5248 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5249 return emitOpError(
"subfield element index is greater than the number "
5250 "of fields in the bundle type");
5260 SmallVector<Operation *, 8> worklist({op});
5264 bool constant =
true;
5270 while (constant && !(worklist.empty()))
5271 TypeSwitch<Operation *>(worklist.pop_back_val())
5272 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5273 if (
auto definingOp = op.getInput().getDefiningOp())
5274 worklist.push_back(definingOp);
5277 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5278 for (
auto &use : op.getResult().getUses())
5279 worklist.push_back(use.getOwner());
5281 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5282 .Default([&](
auto) { constant =
false; });
5291 if (
auto *op = value.getDefiningOp())
5296LogicalResult ConstCastOp::verify() {
5298 return emitOpError() << getInput().getType()
5299 <<
" is not 'const'-castable to "
5300 << getResult().getType();
5304FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5305 std::optional<Location> loc) {
5306 auto inType = type_cast<BundleType>(type);
5308 if (fieldIndex >= inType.getNumElements())
5310 "subfield element index is greater than the "
5311 "number of fields in the bundle type");
5315 return inType.getElementTypePreservingConst(fieldIndex);
5318FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5319 std::optional<Location> loc) {
5320 auto inType = type_cast<OpenBundleType>(type);
5322 if (fieldIndex >= inType.getNumElements())
5324 "subfield element index is greater than the "
5325 "number of fields in the bundle type");
5329 return inType.getElementTypePreservingConst(fieldIndex);
5332bool SubfieldOp::isFieldFlipped() {
5333 BundleType bundle = getInput().getType();
5334 return bundle.getElement(getFieldIndex()).isFlip;
5336bool OpenSubfieldOp::isFieldFlipped() {
5337 auto bundle = getInput().getType();
5338 return bundle.getElement(getFieldIndex()).isFlip;
5341FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5342 std::optional<Location> loc) {
5343 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5344 if (fieldIndex < vectorType.getNumElements())
5345 return vectorType.getElementTypePreservingConst();
5347 "' in vector type ", type);
5352FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5353 std::optional<Location> loc) {
5354 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5355 if (fieldIndex < vectorType.getNumElements())
5356 return vectorType.getElementTypePreservingConst();
5358 "' in vector type ", type);
5364FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5365 OpaqueProperties properties,
5366 mlir::RegionRange regions,
5367 std::optional<Location> loc) {
5368 Adaptor adaptor(operands, attrs, properties, regions);
5369 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5370 auto fieldIndex = adaptor.getFieldIndex();
5372 if (fieldIndex >= inType.getNumElements())
5374 "subtag element index is greater than the "
5375 "number of fields in the enum type");
5379 auto elementType = inType.getElement(fieldIndex).type;
5383FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5384 std::optional<Location> loc) {
5385 if (!type_isa<UIntType>(indexType))
5389 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5391 return vectorType.getElementTypePreservingConst();
5392 return vectorType.getElementType().getAllConstDroppedType();
5400 std::optional<Location> loc) {
5401 auto inType = type_cast<FEnumType>(input);
5402 return UIntType::get(inType.getContext(), inType.getTagWidth());
5405ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5406 OpAsmParser::UnresolvedOperand index;
5407 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5408 Type indexType, elemType;
5410 if (parser.parseOperand(index) || parser.parseComma() ||
5411 parser.parseOperandList(inputs) ||
5412 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5413 parser.parseType(indexType) || parser.parseComma() ||
5414 parser.parseType(elemType))
5417 if (parser.resolveOperand(index, indexType, result.operands))
5420 result.addTypes(elemType);
5422 return parser.resolveOperands(inputs, elemType, result.operands);
5425void MultibitMuxOp::print(OpAsmPrinter &p) {
5426 p <<
" " << getIndex() <<
", ";
5427 p.printOperands(getInputs());
5428 p.printOptionalAttrDict((*this)->getAttrs());
5429 p <<
" : " << getIndex().getType() <<
", " << getType();
5432FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5433 DictionaryAttr attrs,
5434 OpaqueProperties properties,
5435 mlir::RegionRange regions,
5436 std::optional<Location> loc) {
5437 if (operands.size() < 2)
5441 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5442 return operands[1].getType() == op.getType();
5446 return type_cast<FIRRTLType>(operands[1].getType());
5453LogicalResult ObjectSubfieldOp::inferReturnTypes(
5454 MLIRContext *
context, std::optional<mlir::Location> location,
5455 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5456 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5458 inferReturnType(operands, attributes, properties, regions, location);
5461 inferredReturnTypes.push_back(type);
5465Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5466 std::optional<Location> loc) {
5467 auto classType = dyn_cast<ClassType>(inType);
5471 if (classType.getNumElements() <= fieldIndex)
5473 "number of fields in the object");
5474 return classType.getElement(fieldIndex).type;
5477void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5478 auto input = getInput();
5479 auto classType = input.getType();
5480 p <<
' ' << input <<
"[";
5481 p.printKeywordOrString(classType.getElement(getIndex()).name);
5483 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5484 p <<
" : " << classType;
5487ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5488 OperationState &result) {
5489 auto *
context = parser.getContext();
5491 OpAsmParser::UnresolvedOperand input;
5492 std::string fieldName;
5493 ClassType inputType;
5494 if (parser.parseOperand(input) || parser.parseLSquare() ||
5495 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5496 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5497 parser.parseType(inputType) ||
5498 parser.resolveOperand(input, inputType, result.operands))
5501 auto index = inputType.getElementIndex(fieldName);
5503 return parser.emitError(parser.getNameLoc(),
5504 "unknown field " + fieldName +
" in class type ")
5506 result.getOrAddProperties<Properties>().setIndex(
5507 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5509 SmallVector<Type> inferredReturnTypes;
5510 if (failed(inferReturnTypes(
context, result.location, result.operands,
5511 result.attributes.getDictionary(
context),
5512 result.getRawProperties(), result.regions,
5513 inferredReturnTypes)))
5515 result.addTypes(inferredReturnTypes);
5532 int32_t &rhsWidth,
bool &isConstResult,
5533 std::optional<Location> loc) {
5535 auto lhsi = type_dyn_cast<IntType>(lhs);
5536 auto rhsi = type_dyn_cast<IntType>(rhs);
5537 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5540 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5542 else if (!lhsi && rhsi)
5543 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5545 else if (!lhsi && !rhsi)
5546 mlir::emitError(*loc,
"operands must be integer types, not ")
5547 << lhs <<
" and " << rhs;
5549 mlir::emitError(*loc,
"operand signedness must match");
5554 lhsWidth = lhsi.getWidthOrSentinel();
5555 rhsWidth = rhsi.getWidthOrSentinel();
5556 isConstResult = lhsi.isConst() && rhsi.isConst();
5561 assert(op->getNumOperands() == 2 &&
5562 "SameOperandsIntTypeKind on non-binary op");
5563 int32_t lhsWidth, rhsWidth;
5566 op->getOperand(1).getType(), lhsWidth,
5567 rhsWidth, isConstResult, op->getLoc()));
5571 std::optional<Location> loc) {
5572 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5573 bool isConstResult =
false;
5577 if (lhsWidth != -1 && rhsWidth != -1)
5578 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5579 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5584 std::optional<Location> loc) {
5585 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5586 bool isConstResult =
false;
5590 if (lhsWidth != -1 && rhsWidth != -1)
5591 resultWidth = lhsWidth + rhsWidth;
5593 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5598 std::optional<Location> loc) {
5599 int32_t lhsWidth, rhsWidth;
5600 bool isConstResult =
false;
5605 if (type_isa<UIntType>(lhs))
5606 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5609 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5610 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5614 std::optional<Location> loc) {
5615 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5616 bool isConstResult =
false;
5620 if (lhsWidth != -1 && rhsWidth != -1)
5621 resultWidth = std::min(lhsWidth, rhsWidth);
5622 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5627 std::optional<Location> loc) {
5628 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5629 bool isConstResult =
false;
5633 if (lhsWidth != -1 && rhsWidth != -1) {
5634 resultWidth = std::max(lhsWidth, rhsWidth);
5635 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5638 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5642 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5646 std::optional<Location> loc) {
5647 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5650 auto lhsVec = type_cast<FVectorType>(lhs);
5651 auto rhsVec = type_cast<FVectorType>(rhs);
5653 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5658 rhsVec.getElementTypePreservingConst(), loc);
5661 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5662 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5663 lhsVec.isConst() && rhsVec.isConst() &&
5664 elemBaseType.isConst());
5668 std::optional<Location> loc) {
5669 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5672FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5673 OpaqueProperties properties,
5674 mlir::RegionRange regions,
5675 std::optional<Location> loc) {
5677 if (operands.empty())
5678 return UIntType::get(attrs.getContext(), 0);
5681 bool isSigned = type_isa<SIntType>(operands[0].getType());
5682 for (
auto operand : operands) {
5683 auto type = type_dyn_cast<IntType>(operand.getType());
5686 if (type.isSigned() != isSigned)
5688 "all operands must have same signedness");
5692 int32_t resultWidth = 0;
5693 bool isConstResult =
true;
5695 for (
auto operand : operands) {
5696 auto type = type_cast<IntType>(operand.getType());
5697 int32_t width = type.getWidthOrSentinel();
5704 if (resultWidth != -1)
5705 resultWidth += width;
5708 isConstResult &= type.isConst();
5712 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5716 std::optional<Location> loc) {
5717 auto lhsi = type_dyn_cast<IntType>(lhs);
5718 auto rhsui = type_dyn_cast<UIntType>(rhs);
5719 if (!rhsui || !lhsi)
5721 loc,
"first operand should be integer, second unsigned int");
5725 auto width = lhsi.getWidthOrSentinel();
5726 if (width == -1 || !rhsui.getWidth().has_value()) {
5729 auto amount = *rhsui.getWidth();
5732 "shift amount too large: second operand of "
5733 "dshl is wider than 31 bits");
5734 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5735 if (newWidth > INT32_MAX)
5737 loc,
"shift amount too large: first operand shifted by maximum "
5738 "amount exceeds maximum width");
5741 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5742 lhsi.
isConst() && rhsui.isConst());
5746 std::optional<Location> loc) {
5747 auto lhsi = type_dyn_cast<IntType>(lhs);
5748 auto rhsu = type_dyn_cast<UIntType>(rhs);
5751 loc,
"first operand should be integer, second unsigned int");
5752 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5756 std::optional<Location> loc) {
5757 auto lhsi = type_dyn_cast<IntType>(lhs);
5758 auto rhsu = type_dyn_cast<UIntType>(rhs);
5761 loc,
"first operand should be integer, second unsigned int");
5762 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5770 std::optional<Location> loc) {
5771 return UIntType::get(input.getContext(), 32);
5775 std::optional<Location> loc) {
5776 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5779 int32_t width = base.getBitWidthOrSentinel();
5782 return SIntType::get(input.getContext(), width, base.
isConst());
5786 std::optional<Location> loc) {
5787 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5790 int32_t width = base.getBitWidthOrSentinel();
5793 return UIntType::get(input.getContext(), width, base.
isConst());
5797 std::optional<Location> loc) {
5798 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5801 "operand must be single bit scalar base type");
5802 int32_t width = base.getBitWidthOrSentinel();
5803 if (width == -2 || width == 0 || width > 1)
5805 return AsyncResetType::get(input.getContext(), base.
isConst());
5809 std::optional<Location> loc) {
5810 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5813 return ResetType::get(input.getContext(), base.
isConst());
5817 std::optional<Location> loc) {
5818 return ClockType::get(input.getContext(),
isConst(input));
5822 std::optional<Location> loc) {
5823 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5824 auto width = uiType.getWidthOrSentinel();
5827 return SIntType::get(input.getContext(), width, uiType.
isConst());
5830 if (type_isa<SIntType>(input))
5837 std::optional<Location> loc) {
5838 auto inputi = type_dyn_cast<IntType>(input);
5841 int32_t width = inputi.getWidthOrSentinel();
5844 return SIntType::get(input.getContext(), width, inputi.
isConst());
5848 std::optional<Location> loc) {
5849 auto inputi = type_dyn_cast<IntType>(input);
5852 if (isa<UIntType>(inputi))
5854 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5859 std::optional<Location> loc) {
5860 return UIntType::get(input.getContext(), 1,
isConst(input));
5869 std::optional<Location> loc) {
5870 auto inputi = type_dyn_cast<IntType>(input);
5873 loc,
"input type should be the int type but got ", input);
5878 loc,
"high must be equal or greater than low, but got high = ", high,
5886 int32_t width = inputi.getWidthOrSentinel();
5887 if (width != -1 && high >= width)
5890 "high must be smaller than the width of input, but got high = ", high,
5891 ", width = ", width);
5893 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5897 std::optional<Location> loc) {
5899 auto inputi = type_dyn_cast<IntType>(input);
5900 if (amount < 0 || !inputi)
5902 loc,
"operand must have integer type and amount must be >= 0");
5904 int32_t width = inputi.getWidthOrSentinel();
5905 if (width != -1 && amount > width)
5908 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5923 bool isConstCondition,
5924 std::optional<Location> loc) {
5930 if (high.getTypeID() != low.getTypeID())
5931 return emitInferRetTypeError<FIRRTLBaseType>(
5932 loc,
"incompatible mux operand types, true value type: ", high,
5933 ", false value type: ", low);
5935 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5940 if (type_isa<IntType>(low)) {
5945 if (highWidth == -1)
5947 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5952 auto highEnum = type_dyn_cast<FEnumType>(high);
5953 auto lowEnum = type_dyn_cast<FEnumType>(low);
5954 if (lowEnum && highEnum) {
5955 if (lowEnum.getNumElements() != highEnum.getNumElements())
5956 return emitInferRetTypeError<FIRRTLBaseType>(
5957 loc,
"incompatible mux operand types, true value type: ", high,
5958 ", false value type: ", low);
5959 SmallVector<FEnumType::EnumElement> elements;
5960 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5962 if (high.name != low.name || high.value != low.value)
5963 return emitInferRetTypeError<FIRRTLBaseType>(
5964 loc,
"incompatible mux operand types, true value type: ", highEnum,
5965 ", false value type: ", lowEnum);
5972 elements.emplace_back(high.name, high.value, inner);
5974 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5978 auto highVector = type_dyn_cast<FVectorType>(high);
5979 auto lowVector = type_dyn_cast<FVectorType>(low);
5980 if (highVector && lowVector &&
5981 highVector.getNumElements() == lowVector.getNumElements()) {
5983 lowVector.getElementTypePreservingConst(),
5984 isConstCondition, loc);
5987 return FVectorType::get(inner, lowVector.getNumElements(),
5992 auto highBundle = type_dyn_cast<BundleType>(high);
5993 auto lowBundle = type_dyn_cast<BundleType>(low);
5994 if (highBundle && lowBundle) {
5995 auto highElements = highBundle.getElements();
5996 auto lowElements = lowBundle.getElements();
5999 SmallVector<BundleType::BundleElement> newElements;
6001 bool failed =
false;
6003 if (highElements[i].name != lowElements[i].name ||
6004 highElements[i].isFlip != lowElements[i].isFlip) {
6008 auto element = highElements[i];
6010 highBundle.getElementTypePreservingConst(i),
6011 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6014 newElements.push_back(element);
6017 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6019 return emitInferRetTypeError<FIRRTLBaseType>(
6020 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6021 ", false value type: ", low);
6026 return emitInferRetTypeError<FIRRTLBaseType>(
6027 loc,
"invalid mux operand types, true value type: ", high,
6028 ", false value type: ", low);
6033 std::optional<Location> loc) {
6034 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6035 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6036 if (!highType || !lowType)
6041FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6042 DictionaryAttr attrs,
6043 OpaqueProperties properties,
6044 mlir::RegionRange regions,
6045 std::optional<Location> loc) {
6046 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6047 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6048 if (!highType || !lowType)
6054FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6055 DictionaryAttr attrs,
6056 OpaqueProperties properties,
6057 mlir::RegionRange regions,
6058 std::optional<Location> loc) {
6059 SmallVector<FIRRTLBaseType> types;
6061 for (
unsigned i = 1; i < 5; i++) {
6062 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6067 isConst(operands[0].getType()), loc);
6071 result = types.back();
6078 std::optional<Location> loc) {
6079 auto inputi = type_dyn_cast<IntType>(input);
6080 if (amount < 0 || !inputi)
6082 loc,
"pad input must be integer and amount must be >= 0");
6084 int32_t width = inputi.getWidthOrSentinel();
6088 width = std::max<int32_t>(width, amount);
6089 return IntType::get(input.getContext(), inputi.isSigned(), width,
6094 std::optional<Location> loc) {
6095 auto inputi = type_dyn_cast<IntType>(input);
6096 if (amount < 0 || !inputi)
6098 loc,
"shl input must be integer and amount must be >= 0");
6100 int32_t width = inputi.getWidthOrSentinel();
6104 return IntType::get(input.getContext(), inputi.isSigned(), width,
6109 std::optional<Location> loc) {
6110 auto inputi = type_dyn_cast<IntType>(input);
6111 if (amount < 0 || !inputi)
6113 loc,
"shr input must be integer and amount must be >= 0");
6115 int32_t width = inputi.getWidthOrSentinel();
6118 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6119 width = std::max<int32_t>(minWidth, width - amount);
6122 return IntType::get(input.getContext(), inputi.isSigned(), width,
6127 std::optional<Location> loc) {
6129 auto inputi = type_dyn_cast<IntType>(input);
6130 if (amount < 0 || !inputi)
6132 loc,
"tail input must be integer and amount must be >= 0");
6134 int32_t width = inputi.getWidthOrSentinel();
6138 loc,
"amount must be less than or equal operand width");
6149void VerbatimExprOp::getAsmResultNames(
6150 function_ref<
void(Value, StringRef)> setNameFn) {
6154 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6155 auto name = getText();
6157 if (name.starts_with(
"`"))
6158 name = name.drop_front();
6159 name = name.take_while(isOkCharacter);
6161 setNameFn(getResult(), name);
6168void VerbatimWireOp::getAsmResultNames(
6169 function_ref<
void(Value, StringRef)> setNameFn) {
6173 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6174 auto name = getText();
6176 if (name.starts_with(
"`"))
6177 name = name.drop_front();
6178 name = name.take_while(isOkCharacter);
6180 setNameFn(getResult(), name);
6191 op->emitError() <<
"unknown width is not allowed for DPI";
6192 return WalkResult::interrupt();
6194 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6196 return WalkResult::advance();
6198 <<
"integer types used by DPI functions must have a "
6199 "specific bit width; "
6200 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6201 "32(int), 64(longint) "
6202 "or greater than 64, but got "
6204 return WalkResult::interrupt();
6209LogicalResult DPICallIntrinsicOp::verify() {
6210 if (
auto inputNames = getInputNames()) {
6211 if (getInputs().size() != inputNames->size())
6212 return emitError() <<
"inputNames has " << inputNames->size()
6213 <<
" elements but there are " << getInputs().size()
6214 <<
" input arguments";
6216 if (
auto outputName = getOutputName())
6217 if (getNumResults() == 0)
6218 return emitError() <<
"output name is given but there is no result";
6220 auto checkType = [
this](Type type) {
6223 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6224 llvm::all_of(this->getOperandTypes(), checkType));
6227SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6228DPICallIntrinsicOp::computeDataFlow() {
6232 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6234 for (
auto operand : getOperands()) {
6235 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6237 SmallVector<circt::FieldRef> operandFields;
6240 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6244 for (
auto result : getResults())
6247 for (
auto field : operandFields)
6248 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6258LogicalResult HWStructCastOp::verify() {
6260 BundleType bundleType;
6261 hw::StructType structType;
6262 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6263 structType = dyn_cast<hw::StructType>(getType());
6265 return emitError(
"result type must be a struct");
6266 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6267 structType = dyn_cast<hw::StructType>(getOperand().getType());
6269 return emitError(
"operand type must be a struct");
6271 return emitError(
"either source or result type must be a bundle type");
6274 auto firFields = bundleType.getElements();
6275 auto hwFields = structType.getElements();
6276 if (firFields.size() != hwFields.size())
6277 return emitError(
"bundle and struct have different number of fields");
6279 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6280 if (firFields[findex].name.getValue() != hwFields[findex].name)
6281 return emitError(
"field names don't match '")
6282 << firFields[findex].name.getValue() <<
"', '"
6283 << hwFields[findex].name.getValue() <<
"'";
6287 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6288 return emitError(
"size of field '")
6289 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6296LogicalResult BitCastOp::verify() {
6297 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6299 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6301 if (*inTypeBits == *resTypeBits) {
6304 return emitError(
"cannot cast non-'const' input type ")
6305 << getOperand().getType() <<
" to 'const' result type "
6309 return emitError(
"the bitwidth of input (")
6310 << *inTypeBits <<
") and result (" << *resTypeBits
6313 if (!inTypeBits.has_value())
6314 return emitError(
"bitwidth cannot be determined for input operand type ")
6315 << getInput().getType();
6316 return emitError(
"bitwidth cannot be determined for result type ")
6327 NamedAttrList &resultAttrs) {
6328 auto result = parser.parseOptionalAttrDict(resultAttrs);
6329 if (!resultAttrs.get(
"annotations"))
6330 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6336 DictionaryAttr attr,
6337 ArrayRef<StringRef> extraElides = {}) {
6338 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6340 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6341 elidedAttrs.push_back(
"annotations");
6343 elidedAttrs.push_back(
"nameKind");
6345 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6351 NamedAttrList &resultAttrs) {
6354 if (!resultAttrs.get(
"portAnnotations")) {
6355 SmallVector<Attribute, 16> portAnnotations(
6356 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6357 resultAttrs.append(
"portAnnotations",
6358 parser.getBuilder().getArrayAttr(portAnnotations));
6365 DictionaryAttr attr,
6366 ArrayRef<StringRef> extraElides = {}) {
6367 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6369 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6370 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6371 elidedAttrs.push_back(
"portAnnotations");
6380 firrtl::NameKindEnumAttr &result) {
6383 if (!parser.parseOptionalKeyword(&keyword,
6384 {
"interesting_name",
"droppable_name"})) {
6385 auto kind = symbolizeNameKindEnum(keyword);
6386 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6392 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6397 firrtl::NameKindEnumAttr attr,
6398 ArrayRef<StringRef> extraElides = {}) {
6399 if (attr.getValue() != NameKindEnum::DroppableName)
6400 p <<
" " << stringifyNameKindEnum(attr.getValue());
6408 NamedAttrList &resultAttrs) {
6416 DictionaryAttr attrs) {
6417 SmallVector<StringRef, 4> elides;
6419 elides.push_back(Forceable::getForceableAttrName());
6428static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6433static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6444 if (ClassType::parseInterface(parser, type))
6451 type.printInterface(p);
6459 NamedAttrList &resultAttrs) {
6460 auto result = p.parseOptionalAttrDict(resultAttrs);
6461 if (!resultAttrs.get(
"name"))
6462 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6468 DictionaryAttr attr,
6469 ArrayRef<StringRef> extraElides = {}) {
6470 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6471 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6472 elides.push_back(
"name");
6474 p.printOptionalAttrDict(op->getAttrs(), elides);
6478 NamedAttrList &resultAttrs) {
6483 DictionaryAttr attr) {
6488 NamedAttrList &resultAttrs) {
6493 DictionaryAttr attr) {
6495 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6503 DictionaryAttr attr) {
6512 DictionaryAttr attr) {
6521 OpAsmSetValueNameFn setNameFn) {
6524 if (op->getNumResults() == 1)
6525 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6526 setNameFn(op->getResult(0), nameAttr.getValue());
6529void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6533void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6537void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6541void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6544void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6547void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6550void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6553void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6556void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6559void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6562void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6565void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6568void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6571void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6574void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6577void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6580void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6583void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6586void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6589void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6592void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6595void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6598void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6601void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6604void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6607void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6610void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6613void PlusArgsValueIntrinsicOp::getAsmResultNames(
6614 OpAsmSetValueNameFn setNameFn) {
6617void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6620void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6623void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6626void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6629void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6632void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6635void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6638void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6641void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6644void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6647void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6650void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6653void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6656void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6659void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6662void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6665void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6669void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6673void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6677void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6681void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6685void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6689void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6693void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6697void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6701void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6705void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6709void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6713void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6717void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6721void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6725void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6729void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6737void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6741void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6745void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6749void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6753void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6757FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6758 DictionaryAttr attrs,
6759 OpaqueProperties properties,
6760 mlir::RegionRange regions,
6761 std::optional<Location> loc) {
6762 Type inType = operands[0].getType();
6763 auto inRefType = type_dyn_cast<RefType>(inType);
6766 loc,
"ref.resolve operand must be ref type, not ", inType);
6767 return inRefType.getType();
6770FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6771 OpaqueProperties properties,
6772 mlir::RegionRange regions,
6773 std::optional<Location> loc) {
6774 Type inType = operands[0].getType();
6775 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6778 loc,
"ref.send operand must be base type, not ", inType);
6779 return RefType::get(inBaseType.getPassiveType());
6782FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6783 std::optional<Location> loc) {
6784 auto refType = type_dyn_cast<RefType>(type);
6787 auto inType = refType.getType();
6793 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6794 if (fieldIndex < vectorType.getNumElements())
6795 return RefType::get(
6796 vectorType.getElementType().getConstType(
6797 vectorType.isConst() || vectorType.getElementType().isConst()),
6798 refType.getForceable(), refType.getLayer());
6800 "' in RefType of vector type ", refType);
6802 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6803 if (fieldIndex >= bundleType.getNumElements()) {
6805 "subfield element index is greater than "
6806 "the number of fields in the bundle type");
6808 return RefType::get(
6809 bundleType.getElement(fieldIndex)
6811 bundleType.isConst() ||
6812 bundleType.getElement(fieldIndex).type.isConst()),
6813 refType.getForceable(), refType.getLayer());
6817 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6820LogicalResult RefCastOp::verify() {
6824 getOperation(), srcLayers, dstLayers,
6825 "cannot discard layer requirements of input reference",
6826 "discarding layer requirements");
6829LogicalResult RefResolveOp::verify() {
6833 getOperation(), srcLayers, dstLayers,
6834 "ambient layers are insufficient to resolve reference");
6838 auto targetRef = getTarget();
6839 if (targetRef.getModule() !=
6840 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6841 return emitOpError() <<
"has non-local target";
6843 auto target = ns.
lookup(targetRef);
6845 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6847 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6852 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6853 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6854 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6855 << fType <<
" instead of expected " << getType().getType();
6856 diag.attachNote(loc) <<
"target resolves here";
6861 if (target.isPort()) {
6862 auto mod = cast<FModuleLike>(target.getOp());
6863 return checkFinalType(mod.getPortType(target.getPort()),
6864 mod.getPortLocation(target.getPort()));
6866 hw::InnerSymbolOpInterface symOp =
6867 cast<hw::InnerSymbolOpInterface>(target.getOp());
6868 if (!symOp.getTargetResult())
6869 return emitOpError(
"has target that cannot be probed")
6870 .attachNote(symOp.getLoc())
6871 .append(
"target resolves here");
6873 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6874 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6875 return emitOpError(
"is not dominated by target")
6876 .attachNote(symOp.getLoc())
6877 .append(
"target here");
6878 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6881LogicalResult RefForceOp::verify() {
6885 getOperation(), destLayers, ambientLayers,
6886 "has insufficient ambient layers to force its reference");
6889LogicalResult RefForceInitialOp::verify() {
6893 getOperation(), destLayers, ambientLayers,
6894 "has insufficient ambient layers to force its reference");
6897LogicalResult RefReleaseOp::verify() {
6901 getOperation(), destLayers, ambientLayers,
6902 "has insufficient ambient layers to release its reference");
6905LogicalResult RefReleaseInitialOp::verify() {
6909 getOperation(), destLayers, ambientLayers,
6910 "has insufficient ambient layers to release its reference");
6913LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6914 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6916 return emitOpError(
"has an invalid symbol reference");
6918 if (!isa<hw::HierPathOp>(target))
6919 return emitOpError(
"does not target a hierpath op");
6925LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6926 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6928 return emitOpError(
"has an invalid symbol reference");
6930 if (!isa<hw::HierPathOp>(target))
6931 return emitOpError(
"does not target a hierpath op");
6941LogicalResult LayerBlockOp::verify() {
6942 auto layerName = getLayerName();
6943 auto *parentOp = (*this)->getParentOp();
6946 while (isa<WhenOp, MatchOp>(parentOp))
6947 parentOp = parentOp->getParentOp();
6951 auto nestedReferences = layerName.getNestedReferences();
6952 if (nestedReferences.empty()) {
6953 if (!isa<FModuleOp>(parentOp)) {
6954 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6955 "not have a 'firrtl.module' op as a parent";
6956 return diag.attachNote(parentOp->getLoc())
6957 <<
"illegal parent op defined here";
6960 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6961 if (!parentLayerBlock) {
6962 auto diag = emitOpError()
6963 <<
"has a nested layer symbol, but does not have a '"
6964 << getOperationName() <<
"' op as a parent'";
6965 return diag.attachNote(parentOp->getLoc())
6966 <<
"illegal parent op defined here";
6968 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6969 if (parentLayerBlockName.getRootReference() !=
6970 layerName.getRootReference() ||
6971 parentLayerBlockName.getNestedReferences() !=
6972 layerName.getNestedReferences().drop_back()) {
6973 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6974 return diag.attachNote(parentLayerBlock->getLoc())
6975 <<
"illegal parent layer block defined here";
6981 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6982 [&](Operation *op) -> WalkResult {
6984 if (isa<LayerBlockOp>(op))
6985 return WalkResult::skip();
6989 for (
auto operand : op->getOperands()) {
6991 if (
auto *definingOp = operand.getDefiningOp())
6995 auto type = operand.getType();
6998 if (isa<PropertyType>(type)) {
6999 auto diag = emitOpError() <<
"captures a property operand";
7000 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7001 diag.attachNote(op->getLoc()) <<
"operand is used here";
7002 return WalkResult::interrupt();
7007 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7009 if (isa<RefDefineOp>(connect))
7010 return WalkResult::advance();
7017 bool passive =
true;
7019 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7020 passive = type.isPassive();
7029 return WalkResult::advance();
7032 return WalkResult::advance();
7036 <<
"connects to a destination which is defined outside its "
7037 "enclosing layer block";
7038 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7039 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7040 return WalkResult::interrupt();
7043 return WalkResult::advance();
7046 return failure(result.wasInterrupted());
7050LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7052 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7054 return emitOpError(
"invalid symbol reference");
7064void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7065 setNameFn(getResult(),
"time");
7068void HierarchicalModuleNameOp::getAsmResultNames(
7069 OpAsmSetValueNameFn setNameFn) {
7070 setNameFn(getResult(),
"hierarchicalmodulename");
7073ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7074 ::mlir::OperationState &result) {
7076 OpAsmParser::UnresolvedOperand clock, cond;
7077 if (parser.parseOperand(clock) || parser.parseComma() ||
7078 parser.parseOperand(cond) || parser.parseComma())
7082 [&parser](llvm::SMLoc &loc, StringAttr &result,
7083 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7085 loc = parser.getCurrentLocation();
7088 std::string resultStr;
7089 if (parser.parseString(&resultStr))
7091 result = parser.getBuilder().getStringAttr(resultStr);
7094 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7100 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7102 llvm::SMLoc outputFileLoc, formatStringLoc;
7106 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7107 outputFileSubstitutions) ||
7108 parser.parseComma() ||
7111 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7119 Type clockType, condType;
7120 SmallVector<Type> restTypes;
7122 if (parser.parseColon() || parser.parseType(clockType) ||
7123 parser.parseComma() || parser.parseType(condType))
7126 if (succeeded(parser.parseOptionalComma())) {
7127 if (parser.parseTypeList(restTypes))
7132 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7133 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7134 static_cast<int32_t
>(substitutions.size())};
7137 if (parser.resolveOperand(clock, clockType, result.operands) ||
7138 parser.resolveOperand(cond, condType, result.operands) ||
7139 parser.resolveOperands(
7140 outputFileSubstitutions,
7141 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7142 outputFileLoc, result.operands) ||
7143 parser.resolveOperands(
7145 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7146 formatStringLoc, result.operands))
7152void FPrintFOp::print(OpAsmPrinter &p) {
7153 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7154 p.printAttributeWithoutType(getOutputFileAttr());
7155 if (!getOutputFileSubstitutions().
empty()) {
7157 p.printOperands(getOutputFileSubstitutions());
7161 p.printAttributeWithoutType(getFormatStringAttr());
7162 if (!getSubstitutions().
empty()) {
7164 p.printOperands(getSubstitutions());
7168 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7169 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7170 for (
auto type : getOperands().drop_front(2).getTypes()) {
7181LogicalResult FFlushOp::verify() {
7182 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7183 return emitOpError(
"substitutions without output file are not allowed");
7192 auto ref = getInstanceAttr();
7193 auto target = ns.
lookup(ref);
7195 return emitError() <<
"target " << ref <<
" cannot be resolved";
7197 if (!target.isOpOnly())
7198 return emitError() <<
"target " << ref <<
" is not an operation";
7200 auto instance = dyn_cast<InstanceOp>(target.getOp());
7202 return emitError() <<
"target " << ref <<
" is not an instance";
7204 if (!instance.getDoNotPrint())
7205 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7215DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7216 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7217 auto domain = getDomainAttr();
7218 if (!symbolTable.lookupSymbolIn<DomainOp>(circuitOp, domain))
7219 return emitOpError() <<
"references undefined domain '" << domain <<
"'";
7229#define GET_OP_CLASSES
7230#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.
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
SmallSet< SymbolRefAttr, 4, LayerSetCompare > LayerSet
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
Compares two SymbolRefAttr lexicographically, returning true if LHS should be ordered before RHS.
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.