29#include "mlir/IR/BuiltinTypes.h"
30#include "mlir/IR/Diagnostics.h"
31#include "mlir/IR/DialectImplementation.h"
32#include "mlir/IR/PatternMatch.h"
33#include "mlir/IR/SymbolTable.h"
34#include "mlir/Interfaces/FunctionImplementation.h"
35#include "llvm/ADT/BitVector.h"
36#include "llvm/ADT/DenseMap.h"
37#include "llvm/ADT/DenseSet.h"
38#include "llvm/ADT/STLExtras.h"
39#include "llvm/ADT/SmallSet.h"
40#include "llvm/ADT/StringExtras.h"
41#include "llvm/ADT/TypeSwitch.h"
42#include "llvm/Support/Casting.h"
43#include "llvm/Support/FormatVariadic.h"
45using llvm::SmallDenseSet;
46using mlir::RegionRange;
48using namespace firrtl;
49using namespace chirrtl;
56template <
typename RetTy =
FIRRTLType,
typename... Args>
58 const Twine &message, Args &&...args) {
60 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
66 while (Operation *op = val.getDefiningOp()) {
68 TypeSwitch<Operation *, std::optional<bool>>(op)
69 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
73 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
74 .Default([](
auto) {
return false; });
81SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
82MemOp::computeDataFlow() {
85 if (getReadLatency() > 0)
87 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
89 for (
auto memPort : getResults())
90 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
91 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
92 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
93 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
95 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
96 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
98 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
99 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
106 constexpr unsigned int addr = 1 << 0;
107 constexpr unsigned int en = 1 << 1;
108 constexpr unsigned int clk = 1 << 2;
109 constexpr unsigned int data = 1 << 3;
110 constexpr unsigned int mask = 1 << 4;
111 constexpr unsigned int rdata = 1 << 5;
112 constexpr unsigned int wdata = 1 << 6;
113 constexpr unsigned int wmask = 1 << 7;
114 constexpr unsigned int wmode = 1 << 8;
115 constexpr unsigned int def = 1 << 9;
117 auto portType = type_dyn_cast<BundleType>(type);
119 return MemOp::PortKind::Debug;
122 for (
auto elem : portType.getElements()) {
123 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
129 .Case(
"rdata",
rdata)
130 .Case(
"wdata",
wdata)
131 .Case(
"wmask",
wmask)
132 .Case(
"wmode",
wmode)
136 return MemOp::PortKind::Read;
138 return MemOp::PortKind::Write;
140 return MemOp::PortKind::ReadWrite;
141 return MemOp::PortKind::Debug;
156 llvm_unreachable(
"Unsupported Flow type.");
164 return "source flow";
168 return "duplex flow";
171 llvm_unreachable(
"Unsupported Flow type.");
176 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
177 auto *op = val.getParentBlock()->getParentOp();
178 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
179 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
180 if (direction == Direction::Out)
183 return accumulatedFlow;
186 Operation *op = val.getDefiningOp();
188 return TypeSwitch<Operation *, Flow>(op)
189 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
190 return foldFlow(op.getInput(), op.isFieldFlipped()
194 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
195 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
197 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
198 [](
auto) {
return Flow::Duplex; })
199 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
200 auto resultNo = cast<OpResult>(val).getResultNumber();
201 if (inst.getPortDirection(resultNo) == Direction::Out)
202 return accumulatedFlow;
205 .Case<MemOp>([&](
auto op) {
207 if (type_isa<RefType>(val.getType()))
211 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
212 auto input = op.getInput();
213 auto *inputOp = input.getDefiningOp();
216 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
217 auto classType = input.getType();
218 auto direction = classType.getElement(op.getIndex()).direction;
219 if (direction == Direction::In)
230 auto classType = input.getType();
231 auto direction = classType.getElement(op.getIndex()).direction;
232 if (direction == Direction::In)
235 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
237 input = op.getInput();
238 inputOp = input.getDefiningOp();
242 return accumulatedFlow;
246 .Default([&](
auto) {
return accumulatedFlow; });
252 Operation *op = val.getDefiningOp();
254 return DeclKind::Port;
256 return TypeSwitch<Operation *, DeclKind>(op)
257 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
258 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
260 .Default([](
auto) {
return DeclKind::Other; });
264 if (
auto module = dyn_cast<FModuleLike>(op))
265 return module.getNumPorts();
266 return op->getNumResults();
280 if (
auto *op = value.getDefiningOp())
282 auto arg = dyn_cast<BlockArgument>(value);
283 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
286 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
293 OpAsmSetValueNameFn setNameFn) {
297 auto *block = ®ion.front();
300 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
302 if (!argAttr || argAttr.size() != block->getNumArguments())
305 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
306 auto str = cast<StringAttr>(argAttr[i]).getValue();
308 setNameFn(block->getArgument(i), str);
314 firrtl::NameKindEnumAttr &result);
325 for (; op !=
nullptr; op = op->getParentOp()) {
326 if (
auto module = dyn_cast<FModuleLike>(op)) {
327 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
328 result.insert(layers.begin(), layers.end());
331 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
332 result.insert(layerblock.getLayerName());
350 if (
auto type = dyn_cast<RefType>(value.getType()))
351 if (
auto layer = type.getLayer())
352 result.insert(type.getLayer());
361 mlir::SymbolRefAttr dstLayer) {
371 if (srcLayer.getRootReference() != dstLayer.getRootReference())
374 auto srcNames = srcLayer.getNestedReferences();
375 auto dstNames = dstLayer.getNestedReferences();
376 if (dstNames.size() < srcNames.size())
379 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
380 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
387 if (dstLayers.contains(srcLayer))
392 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
401 SmallVectorImpl<SymbolRefAttr> &missing) {
402 for (
auto srcLayer : src)
404 missing.push_back(srcLayer);
407 return missing.empty();
412 const Twine &errorMsg,
413 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
414 SmallVector<SymbolRefAttr> missing;
417 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
426void CircuitOp::build(OpBuilder &builder, OperationState &result,
427 StringAttr name, ArrayAttr annotations) {
429 result.getOrAddProperties<Properties>().setName(name);
432 annotations = builder.getArrayAttr({});
433 result.getOrAddProperties<Properties>().setAnnotations(annotations);
436 Region *bodyRegion = result.addRegion();
438 bodyRegion->push_back(body);
442 NamedAttrList &resultAttrs) {
443 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
444 if (!resultAttrs.get(
"annotations"))
445 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
451 DictionaryAttr attr) {
453 SmallVector<StringRef> elidedAttrs = {
"name"};
455 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
456 if (annotationsAttr.empty())
457 elidedAttrs.push_back(
"annotations");
459 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
462LogicalResult CircuitOp::verifyRegions() {
467 emitOpError(
"must have a non-empty name");
471 mlir::SymbolTable symtbl(getOperation());
473 auto *mainModule = symtbl.lookup(
main);
475 return emitOpError().append(
476 "does not contain module with same name as circuit");
477 if (!isa<FModuleLike>(mainModule))
478 return mainModule->emitError(
479 "entity with name of circuit must be a module");
480 if (symtbl.getSymbolVisibility(mainModule) !=
481 mlir::SymbolTable::Visibility::Public)
482 return mainModule->emitError(
"main module must be public");
487 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
489 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
493 auto defname = extModule.getDefnameAttr();
499 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
500 return extModule.emitOpError()
501 .append(
"attribute 'defname' with value ", defname,
502 " conflicts with the name of another module in the circuit")
503 .attachNote(collidingModule.getLoc())
504 .append(
"previous module declared here");
512 FExtModuleOp collidingExtModule;
513 if (
auto &value = defnameMap[defname]) {
514 collidingExtModule = value;
515 if (!value.getParameters().empty() && extModule.getParameters().empty())
525 SmallVector<PortInfo> ports = extModule.getPorts();
526 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
528 if (ports.size() != collidingPorts.size())
529 return extModule.emitOpError()
530 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
531 " ports which is different from a previously defined "
532 "extmodule with the same 'defname' which has ",
533 collidingPorts.size(),
" ports")
534 .attachNote(collidingExtModule.getLoc())
535 .append(
"previous extmodule definition occurred here");
541 for (
auto p :
llvm::zip(ports, collidingPorts)) {
542 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
543 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
546 return extModule.emitOpError()
547 .append(
"with 'defname' attribute ", defname,
548 " has a port with name ", aName,
549 " which does not match the name of the port in the same "
550 "position of a previously defined extmodule with the same "
551 "'defname', expected port to have name ",
553 .attachNote(collidingExtModule.getLoc())
554 .append(
"previous extmodule definition occurred here");
556 if (!extModule.getParameters().empty() ||
557 !collidingExtModule.getParameters().empty()) {
559 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
560 aType = base.getWidthlessType();
561 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
562 bType = base.getWidthlessType();
565 return extModule.emitOpError()
566 .append(
"with 'defname' attribute ", defname,
567 " has a port with name ", aName,
568 " which has a different type ", aType,
569 " which does not match the type of the port in the same "
570 "position of a previously defined extmodule with the same "
571 "'defname', expected port to have type ",
573 .attachNote(collidingExtModule.getLoc())
574 .append(
"previous extmodule definition occurred here");
579 SmallVector<FModuleOp, 1> dutModules;
582 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
584 dutModules.push_back(moduleOp);
589 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
590 if (verifyExtModule(extModule).failed())
596 if (dutModules.size() > 1) {
597 auto diag = dutModules[0]->emitOpError()
598 <<
"is annotated as the design-under-test (DUT), but other "
599 "modules are also annotated";
600 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
601 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
608Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
615 SmallVector<PortInfo> results;
616 results.reserve(module.getNumPorts());
617 ArrayRef<Attribute> domains =
module.getDomainInfo();
618 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
619 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
620 module.getPortDirection(i), module.getPortSymbolAttr(i),
621 module.getPortLocation(i),
622 AnnotationSet::forPort(module, i),
623 domains.empty() ? Attribute{} : domains[i]});
628SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
630SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
632SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
634SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
637 if (dir == Direction::In)
638 return hw::ModulePort::Direction::Input;
639 if (dir == Direction::Out)
640 return hw::ModulePort::Direction::Output;
641 assert(0 &&
"invalid direction");
646 SmallVector<hw::PortInfo> results;
647 auto aname = StringAttr::get(module.getContext(),
648 hw::HWModuleLike::getPortSymbolAttrName());
649 auto emptyDict = DictionaryAttr::get(module.getContext());
650 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
651 auto sym =
module.getPortSymbolAttr(i);
653 {{
module.getPortNameAttr(i), module.getPortType(i),
654 dirFtoH(module.getPortDirection(i))},
656 sym ? DictionaryAttr::get(
658 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
660 module.getPortLocation(i)});
665SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
666 return ::getPortListImpl(*
this);
669SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
670 return ::getPortListImpl(*
this);
673SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
674 return ::getPortListImpl(*
this);
677SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
678 return ::getPortListImpl(*
this);
682 auto sym =
module.getPortSymbolAttr(idx);
683 auto attrs = sym ? DictionaryAttr::getWithSorted(
685 ArrayRef(mlir::NamedAttribute(
686 hw::HWModuleLike::getPortSymbolAttrName(), sym)))
687 : DictionaryAttr::get(module.getContext());
688 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
689 dirFtoH(module.getPortDirection(idx))},
692 module.getPortLocation(idx)};
696 return ::getPortImpl(*
this, idx);
700 return ::getPortImpl(*
this, idx);
704 return ::getPortImpl(*
this, idx);
708 return ::getPortImpl(*
this, idx);
712BlockArgument FModuleOp::getArgument(
size_t portNumber) {
719 Attribute domainInfoAttr,
720 ArrayRef<unsigned> indexMap) {
722 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
723 if (!di || di.empty())
724 return domainInfoAttr;
727 SmallVector<Attribute> domainInfo;
728 for (
auto attr : di) {
729 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
730 auto newIdx = indexMap[oldIdx];
731 if (oldIdx == newIdx)
732 domainInfo.push_back(attr);
734 domainInfo.push_back(IntegerAttr::get(
735 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
737 return ArrayAttr::get(
context, domainInfo);
744 ArrayRef<std::pair<unsigned, PortInfo>> ports) {
747 unsigned oldNumArgs = op.getNumPorts();
748 unsigned newNumArgs = oldNumArgs + ports.size();
751 SmallVector<unsigned> indexMap(oldNumArgs);
753 for (
size_t i = 0; i < oldNumArgs; ++i) {
754 while (inserted < ports.size() && ports[inserted].first == i)
756 indexMap[i] = i + inserted;
760 auto existingDirections = op.getPortDirectionsAttr();
761 ArrayRef<Attribute> existingNames = op.getPortNames();
762 ArrayRef<Attribute> existingTypes = op.getPortTypes();
763 ArrayRef<Attribute> existingLocs = op.getPortLocations();
764 assert(existingDirections.size() == oldNumArgs);
765 assert(existingNames.size() == oldNumArgs);
766 assert(existingTypes.size() == oldNumArgs);
767 assert(existingLocs.size() == oldNumArgs);
769 SmallVector<bool> newDirections;
770 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
772 newDirections.reserve(newNumArgs);
773 newNames.reserve(newNumArgs);
774 newTypes.reserve(newNumArgs);
775 newDomains.reserve(newNumArgs);
776 newAnnos.reserve(newNumArgs);
777 newSyms.reserve(newNumArgs);
778 newLocs.reserve(newNumArgs);
780 auto emptyArray = ArrayAttr::get(op.getContext(), {});
783 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
784 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
785 newDirections.push_back(existingDirections[oldIdx]);
786 newNames.push_back(existingNames[oldIdx]);
787 newTypes.push_back(existingTypes[oldIdx]);
789 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), indexMap));
790 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
791 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
792 newLocs.push_back(existingLocs[oldIdx]);
797 for (
auto [idx, port] : ports) {
798 migrateOldPorts(idx);
800 newNames.push_back(port.name);
801 newTypes.push_back(TypeAttr::get(port.type));
804 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
806 auto annos = port.annotations.getArrayAttr();
807 newAnnos.push_back(annos ? annos : emptyArray);
808 newSyms.push_back(port.sym);
809 newLocs.push_back(port.loc);
812 migrateOldPorts(oldNumArgs);
816 if (llvm::all_of(newAnnos, [](Attribute attr) {
817 return cast<ArrayAttr>(attr).empty();
823 if (llvm::all_of(newDomains, [](Attribute attr) {
826 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
827 return arrayAttr.empty();
833 op->setAttr(
"portDirections",
835 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
836 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
837 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
838 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
839 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
840 op.setPortSymbols(newSyms);
841 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
852 ArrayAttr domainInfoAttr,
853 const llvm::BitVector &portIndices,
854 bool supportsEmptyAttr) {
855 if (supportsEmptyAttr && domainInfoAttr.empty())
856 return domainInfoAttr;
859 SmallVector<unsigned> indexMap(portIndices.size());
861 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
862 indexMap[i] = i - deleted;
869 auto getEmpty = [&]() {
871 eEmpty = ArrayAttr::get(
context, {});
876 SmallVector<Attribute> newDomainInfo;
877 newDomainInfo.reserve(portIndices.size() - portIndices.count());
878 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
880 if (portIndices.test(i))
883 if (domainInfoAttr.empty()) {
884 newDomainInfo.push_back(getEmpty());
887 auto attr = domainInfoAttr[i];
889 auto domains = dyn_cast<ArrayAttr>(attr);
890 if (!domains || domains.empty()) {
891 newDomainInfo.push_back(attr);
895 SmallVector<Attribute> newDomains;
896 for (
auto domain : domains) {
898 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
899 if (portIndices.test(oldIdx))
902 auto newIdx = indexMap[oldIdx];
903 if (oldIdx == newIdx) {
904 newDomains.push_back(domain);
908 newDomains.push_back(IntegerAttr::get(
909 IntegerType::get(
context, 32, IntegerType::Unsigned), newIdx));
911 newDomainInfo.push_back(ArrayAttr::get(
context, newDomains));
914 return ArrayAttr::get(
context, newDomainInfo);
918static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
919 if (portIndices.none())
923 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
924 ArrayRef<Attribute> portNames = op.getPortNames();
925 ArrayRef<Attribute> portTypes = op.getPortTypes();
926 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
927 ArrayRef<Attribute> portSyms = op.getPortSymbols();
928 ArrayRef<Attribute> portLocs = op.getPortLocations();
929 ArrayRef<Attribute> portDomains = op.getDomainInfo();
931 auto numPorts = op.getNumPorts();
933 assert(portDirections.size() == numPorts);
934 assert(portNames.size() == numPorts);
935 assert(portAnnos.size() == numPorts || portAnnos.empty());
936 assert(portTypes.size() == numPorts);
937 assert(portSyms.size() == numPorts || portSyms.empty());
938 assert(portLocs.size() == numPorts);
939 assert(portDomains.size() == numPorts || portDomains.empty());
941 SmallVector<bool> newPortDirections =
942 removeElementsAtIndices<bool>(portDirections, portIndices);
943 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
951 op->setAttr(
"portDirections",
953 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
954 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
955 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
956 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
957 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
958 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
959 op->setAttr(
"domainInfo",
964void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
965 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
968void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
969 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
972void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
973 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
976void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
977 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
984void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
989 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
992 auto &[index, port] = ports[i];
993 body->insertArgument(index + i, port.type, port.loc);
997void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1001void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1002 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1008void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1009 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1012template <
typename OpTy>
1014 StringAttr name, ArrayRef<PortInfo> ports) {
1016 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1017 properties.setSymName(name);
1020 SmallVector<Direction, 4> portDirections;
1021 SmallVector<Attribute, 4> portNames, portTypes, portSyms, portLocs,
1023 portDirections.reserve(ports.size());
1024 portNames.reserve(ports.size());
1025 portTypes.reserve(ports.size());
1026 portSyms.reserve(ports.size());
1027 portLocs.reserve(ports.size());
1028 portDomains.reserve(ports.size());
1030 for (
const auto &port : ports) {
1031 portDirections.push_back(port.direction);
1032 portNames.push_back(port.name);
1033 portTypes.push_back(TypeAttr::get(port.type));
1034 portSyms.push_back(port.sym);
1035 portLocs.push_back(port.loc);
1036 portDomains.push_back(port.domains);
1038 if (llvm::all_of(portDomains, [](Attribute attr) {
1041 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1042 return arrayAttr.empty();
1045 portDomains.clear();
1047 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1050 properties.setPortDirections(
1052 properties.setPortNames(builder.getArrayAttr(portNames));
1053 properties.setPortTypes(builder.getArrayAttr(portTypes));
1054 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1055 properties.setPortLocations(builder.getArrayAttr(portLocs));
1056 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1061template <
typename OpTy>
1063 StringAttr name, ArrayRef<PortInfo> ports,
1064 ArrayAttr annotations, ArrayAttr layers) {
1065 buildModuleLike<OpTy>(builder, result, name, ports);
1066 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1069 annotations = builder.getArrayAttr({});
1070 properties.setAnnotations(annotations);
1074 SmallVector<Attribute, 4> portAnnotations;
1075 for (
const auto &port : ports)
1076 portAnnotations.push_back(port.annotations.getArrayAttr());
1077 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1078 return cast<ArrayAttr>(attr).empty();
1080 portAnnotations.clear();
1081 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1085 layers = builder.getArrayAttr({});
1086 properties.setLayers(layers);
1089template <
typename OpTy>
1090static void buildClass(OpBuilder &builder, OperationState &result,
1091 StringAttr name, ArrayRef<PortInfo> ports) {
1092 return buildModuleLike<OpTy>(builder, result, name, ports);
1095void FModuleOp::build(OpBuilder &builder, OperationState &result,
1096 StringAttr name, ConventionAttr convention,
1097 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1099 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1100 auto &properties = result.getOrAddProperties<Properties>();
1101 properties.setConvention(convention);
1104 auto *bodyRegion = result.regions[0].get();
1106 bodyRegion->push_back(body);
1109 for (
auto &elt : ports)
1110 body->addArgument(elt.type, elt.loc);
1113void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1114 StringAttr name, ConventionAttr convention,
1115 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1116 StringRef defnameAttr, ArrayAttr annotations,
1117 ArrayAttr parameters, ArrayAttr layers,
1118 ArrayAttr externalRequirements) {
1119 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1120 auto &properties = result.getOrAddProperties<Properties>();
1121 properties.setConvention(convention);
1123 knownLayers = builder.getArrayAttr({});
1124 properties.setKnownLayers(knownLayers);
1125 if (!defnameAttr.empty())
1126 properties.setDefname(builder.getStringAttr(defnameAttr));
1128 parameters = builder.getArrayAttr({});
1129 properties.setParameters(parameters);
1130 if (externalRequirements)
1131 properties.setExternalRequirements(externalRequirements);
1134void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1135 StringAttr name, ArrayRef<PortInfo> ports,
1136 StringRef intrinsicNameStr, ArrayAttr annotations,
1137 ArrayAttr parameters, ArrayAttr layers) {
1138 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1139 auto &properties = result.getOrAddProperties<Properties>();
1140 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1142 parameters = builder.getArrayAttr({});
1143 properties.setParameters(parameters);
1146void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1147 StringAttr name, ArrayRef<PortInfo> ports,
1148 uint32_t numReadPorts, uint32_t numWritePorts,
1149 uint32_t numReadWritePorts, uint32_t dataWidth,
1150 uint32_t maskBits, uint32_t readLatency,
1151 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1152 ArrayAttr annotations, ArrayAttr layers) {
1153 auto *
context = builder.getContext();
1154 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1155 auto ui32Type = IntegerType::get(
context, 32, IntegerType::Unsigned);
1156 auto ui64Type = IntegerType::get(
context, 64, IntegerType::Unsigned);
1157 auto &properties = result.getOrAddProperties<Properties>();
1158 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1159 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1160 properties.setNumReadWritePorts(
1161 IntegerAttr::get(ui32Type, numReadWritePorts));
1162 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1163 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1164 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1165 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1166 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1167 properties.setExtraPorts(ArrayAttr::get(
context, {}));
1168 properties.setRuw(RUWBehaviorAttr::get(
context, ruw));
1185 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1186 ArrayRef<Attribute> portAnnotations,
1187 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1188 ArrayRef<Attribute> domainInfo) {
1191 bool printedNamesDontMatch =
false;
1193 mlir::OpPrintingFlags flags;
1196 DenseMap<unsigned, std::string> ssaNames;
1197 auto getSsaName = [&](
unsigned idx) -> StringRef {
1199 auto itr = ssaNames.find(idx);
1200 if (itr != ssaNames.end())
1201 return itr->getSecond();
1205 SmallString<32> resultNameStr;
1207 llvm::raw_svector_ostream tmpStream(resultNameStr);
1208 p.printOperand(block->getArgument(idx), tmpStream);
1211 auto portName = cast<StringAttr>(portNames[idx]).getValue();
1212 if (tmpStream.str().drop_front() != portName)
1213 printedNamesDontMatch =
true;
1214 return ssaNames.insert({idx, tmpStream.str().str()}).first->getSecond();
1217 auto name = cast<StringAttr>(portNames[idx]).getValue();
1218 return ssaNames.insert({idx, name.str()}).first->getSecond();
1224 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1233 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1237 p.printKeywordOrString(getSsaName(i));
1242 p.printType(portType);
1245 if (!portSyms.empty()) {
1246 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1248 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1256 if (!domainInfo.empty()) {
1257 auto domains = cast<ArrayAttr>(domainInfo[i]);
1258 if (!domains.empty()) {
1260 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1261 p << getSsaName(cast<IntegerAttr>(attr).getUInt());
1269 if (!portAnnotations.empty() &&
1270 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1272 p.printAttribute(portAnnotations[i]);
1279 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1280 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1284 return printedNamesDontMatch;
1290 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1291 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1292 SmallVectorImpl<Direction> &portDirections,
1293 SmallVectorImpl<Attribute> &portNames,
1294 SmallVectorImpl<Attribute> &portTypes,
1295 SmallVectorImpl<Attribute> &portAnnotations,
1296 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1297 SmallVectorImpl<Attribute> &domains) {
1298 auto *
context = parser.getContext();
1301 DenseMap<Attribute, size_t> domainIndex;
1304 using DomainAndLoc = std::pair<Attribute, llvm::SMLoc>;
1305 DenseMap<size_t, SmallVector<DomainAndLoc>> domainStrings;
1307 auto parseArgument = [&]() -> ParseResult {
1309 if (succeeded(parser.parseOptionalKeyword(
"out")))
1310 portDirections.push_back(Direction::Out);
1311 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1312 portDirections.push_back(Direction::In);
1319 auto portIdx = portNames.size();
1321 if (hasSSAIdentifiers) {
1322 OpAsmParser::Argument arg;
1323 if (parser.parseArgument(arg))
1325 entryArgs.push_back(arg);
1329 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1330 "Unknown MLIR name");
1331 if (
isdigit(arg.ssaName.name[1]))
1332 portNames.push_back(StringAttr::get(
context,
""));
1334 portNames.push_back(
1335 StringAttr::get(
context, arg.ssaName.name.drop_front()));
1338 irLoc = arg.ssaName.location;
1342 irLoc = parser.getCurrentLocation();
1343 std::string portName;
1344 if (parser.parseKeywordOrString(&portName))
1346 portNames.push_back(StringAttr::get(
context, portName));
1351 if (parser.parseColonType(portType))
1353 portTypes.push_back(TypeAttr::get(portType));
1354 if (isa<DomainType>(portType))
1355 domainIndex[portNames.back()] = portIdx;
1357 if (hasSSAIdentifiers)
1358 entryArgs.back().type = portType;
1361 if (supportsSymbols) {
1362 hw::InnerSymAttr innerSymAttr;
1363 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1364 NamedAttrList dummyAttrs;
1365 if (parser.parseCustomAttributeWithFallback(
1366 innerSymAttr, ::mlir::Type{},
1368 return ::mlir::failure();
1371 portSyms.push_back(innerSymAttr);
1377 Attribute domainInfo = ArrayAttr::get(
context, {});
1378 if (supportsDomains) {
1379 if (
auto domainType = dyn_cast<DomainType>(portType)) {
1381 domainInfo = ArrayAttr::get(
context, {});
1382 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1383 auto result = parser.parseCommaSeparatedList(
1384 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1386 if (hasSSAIdentifiers) {
1387 OpAsmParser::Argument arg;
1388 if (parser.parseArgument(arg))
1391 StringAttr::get(
context, arg.ssaName.name.drop_front());
1393 std::string portName;
1394 if (parser.parseKeywordOrString(&portName))
1396 argName = StringAttr::get(
context, portName);
1398 domainStrings[portIdx].push_back({argName, irLoc});
1405 domainInfo =
nullptr;
1408 domains.push_back(domainInfo);
1412 auto parseResult = parser.parseOptionalAttribute(annos);
1413 if (!parseResult.has_value())
1414 annos = parser.getBuilder().getArrayAttr({});
1415 else if (failed(*parseResult))
1417 portAnnotations.push_back(annos);
1420 std::optional<Location> maybeLoc;
1421 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1423 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1424 portLocs.push_back(loc);
1425 if (hasSSAIdentifiers)
1426 entryArgs.back().sourceLoc = loc;
1435 if (failed(parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1441 for (
auto [portIdx, domainInfo] : llvm::enumerate(domains)) {
1446 SmallVector<Attribute> portDomains;
1447 for (
auto [domainName, loc] : domainStrings[portIdx]) {
1448 auto index = domainIndex.find(domainName);
1449 if (index == domainIndex.end()) {
1450 parser.emitError(loc) <<
"domain name '" << domainName <<
"' not found";
1453 portDomains.push_back(IntegerAttr::get(
1454 IntegerType::get(
context, 32, IntegerType::Unsigned), index->second));
1456 domains[portIdx] = parser.getBuilder().getArrayAttr(portDomains);
1464 ArrayAttr parameters) {
1465 if (!parameters || parameters.empty())
1469 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1470 auto paramAttr = cast<ParamDeclAttr>(param);
1471 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1472 if (
auto value = paramAttr.getValue()) {
1474 p.printAttributeWithoutType(value);
1480template <
typename ModuleTy>
1485 StringRef visibilityAttrName =
1486 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
1487 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1488 p << visibility.getValue() <<
' ';
1491 p.printSymbolName(cast<mlir::SymbolOpInterface>(op.getOperation()).getName());
1498 Block *body =
nullptr;
1499 if (!op->getRegion(0).empty())
1500 body = &op->getRegion(0).front();
1503 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1504 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1505 op.getDomainInfo());
1507 SmallVector<StringRef, 13> omittedAttrs = {
1508 ModuleTy::getSymNameAttrName(op->getName()),
1518 if (op.getConvention() == Convention::Internal)
1519 omittedAttrs.push_back(
"convention");
1523 if (!needPortNamesAttr)
1524 omittedAttrs.push_back(
"portNames");
1527 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1528 omittedAttrs.push_back(
"annotations");
1531 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1532 if (knownLayers.empty())
1533 omittedAttrs.push_back(
"knownLayers");
1536 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1538 omittedAttrs.push_back(
"layers");
1541 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1542 if (extReqs.empty())
1543 omittedAttrs.push_back(
"externalRequirements");
1545 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1548void FExtModuleOp::print(OpAsmPrinter &p) {
1549 printFModuleLikeOp<FExtModuleOp>(p, *
this);
1552void FIntModuleOp::print(OpAsmPrinter &p) {
1553 printFModuleLikeOp<FIntModuleOp>(p, *
this);
1556void FMemModuleOp::print(OpAsmPrinter &p) {
1557 printFModuleLikeOp<FMemModuleOp>(p, *
this);
1560void FModuleOp::print(OpAsmPrinter &p) {
1561 printFModuleLikeOp<FModuleOp>(p, *
this);
1566 Region &fbody = getBody();
1567 if (!fbody.empty()) {
1569 p.printRegion(fbody,
false,
1581 SmallVectorImpl<Attribute> ¶meters) {
1583 return parser.parseCommaSeparatedList(
1584 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1589 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1593 if (succeeded(parser.parseOptionalEqual())) {
1594 if (parser.parseAttribute(value, type))
1598 auto &builder = parser.getBuilder();
1599 parameters.push_back(ParamDeclAttr::get(
1600 builder.getContext(), builder.getStringAttr(name), type, value));
1607 ArrayAttr ¶meters) {
1608 SmallVector<Attribute> parseParameters;
1612 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1617template <
typename Properties,
typename =
void>
1620template <
typename Properties>
1622 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1623 : std::true_type {};
1625template <
typename OpTy>
1627 OperationState &result,
1628 bool hasSSAIdentifiers) {
1629 auto *
context = result.getContext();
1630 auto &builder = parser.getBuilder();
1631 using Properties =
typename OpTy::Properties;
1632 auto &properties = result.getOrAddProperties<Properties>();
1636 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1639 StringAttr nameAttr;
1640 if (parser.parseSymbolName(nameAttr))
1642 properties.setSymName(nameAttr);
1646 SmallVector<Attribute, 4> parameters;
1649 properties.setParameters(builder.getArrayAttr(parameters));
1653 SmallVector<OpAsmParser::Argument> entryArgs;
1654 SmallVector<Direction, 4> portDirections;
1655 SmallVector<Attribute, 4> portNames;
1656 SmallVector<Attribute, 4> portTypes;
1657 SmallVector<Attribute, 4> portAnnotations;
1658 SmallVector<Attribute, 4> portSyms;
1659 SmallVector<Attribute, 4> portLocs;
1660 SmallVector<Attribute, 4> domains;
1662 true, entryArgs, portDirections,
1663 portNames, portTypes, portAnnotations, portSyms,
1668 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1671 assert(portNames.size() == portTypes.size());
1677 properties.setPortDirections(
1681 properties.setPortNames(builder.getArrayAttr(portNames));
1684 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1688 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1689 return !cast<ArrayAttr>(anno).empty();
1691 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1693 properties.setPortAnnotations(builder.getArrayAttr({}));
1696 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1697 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1700 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1703 properties.setAnnotations(builder.getArrayAttr({}));
1706 if (llvm::all_of(domains, [&](Attribute attr) {
1707 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1708 return arrayAttr && arrayAttr.empty();
1710 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1712 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1715 auto *body = result.addRegion();
1717 if (hasSSAIdentifiers) {
1718 if (parser.parseRegion(*body, entryArgs))
1721 body->push_back(
new Block());
1726ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1727 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1730 auto &properties = result.getOrAddProperties<Properties>();
1731 properties.setConvention(
1732 ConventionAttr::get(result.getContext(), Convention::Internal));
1733 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1737ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1738 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1741 auto &properties = result.getOrAddProperties<Properties>();
1742 properties.setConvention(
1743 ConventionAttr::get(result.getContext(), Convention::Internal));
1744 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1748ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1749 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1753ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1754 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1758LogicalResult FModuleOp::verify() {
1761 auto portTypes = getPortTypes();
1762 auto portLocs = getPortLocations();
1763 auto numPorts = portTypes.size();
1766 if (body->getNumArguments() != numPorts)
1767 return emitOpError(
"entry block must have ")
1768 << numPorts <<
" arguments to match module signature";
1771 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1772 if (arg.getType() != cast<TypeAttr>(type).getValue())
1773 return emitOpError(
"block argument types should match signature types");
1774 if (arg.getLoc() != cast<LocationAttr>(loc))
1776 "block argument locations should match signature locations");
1782LogicalResult FExtModuleOp::verify() {
1783 auto params = getParameters();
1785 auto checkParmValue = [&](Attribute elt) ->
bool {
1786 auto param = cast<ParamDeclAttr>(elt);
1787 auto value = param.getValue();
1788 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1790 emitError() <<
"has unknown extmodule parameter value '"
1791 << param.getName().getValue() <<
"' = " << value;
1795 if (!llvm::all_of(params, checkParmValue))
1800 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1803 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1804 for (
auto attr : getPortTypes()) {
1805 auto type = cast<TypeAttr>(attr).getValue();
1806 if (
auto refType = type_dyn_cast<RefType>(type))
1807 if (
auto layer = refType.getLayer())
1808 referenced.insert(layer);
1812 "references unknown layers",
"unknown layers");
1815LogicalResult FIntModuleOp::verify() {
1816 auto params = getParameters();
1820 auto checkParmValue = [&](Attribute elt) ->
bool {
1821 auto param = cast<ParamDeclAttr>(elt);
1822 auto value = param.getValue();
1823 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1825 emitError() <<
"has unknown intmodule parameter value '"
1826 << param.getName().getValue() <<
"' = " << value;
1830 if (!llvm::all_of(params, checkParmValue))
1837 CircuitOp circuitOp,
1838 SymbolTableCollection &symbolTable,
1840 auto layer = refType.getLayer();
1843 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1845 return emitError(loc) << start <<
" associated with layer '" << layer
1846 <<
"', but this layer was not defined";
1847 if (!isa<LayerOp>(layerOp)) {
1848 auto diag = emitError(loc)
1849 << start <<
" associated with layer '" << layer
1850 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1851 << LayerOp::getOperationName() <<
"' op";
1852 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1858 SymbolTableCollection &symbolTable) {
1860 auto circuitOp =
module->getParentOfType<CircuitOp>();
1861 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1862 auto type =
module.getPortType(i);
1864 if (
auto refType = type_dyn_cast<RefType>(type)) {
1866 refType, module.getPortLocation(i), circuitOp, symbolTable,
1867 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1872 if (
auto classType = dyn_cast<ClassType>(type)) {
1873 auto className = classType.getNameAttr();
1874 auto classOp = dyn_cast_or_null<ClassLike>(
1875 symbolTable.lookupSymbolIn(circuitOp, className));
1877 return module.emitOpError() << "references unknown class " << className;
1880 if (failed(classOp.verifyType(classType,
1881 [&]() { return module.emitOpError(); })))
1886 if (
auto domainType = dyn_cast<DomainType>(type)) {
1888 domainType.verifySymbolUses(module.getOperation(), symbolTable)))
1897LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1901 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1902 for (
auto layer : getLayers()) {
1903 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1904 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1911FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1915 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1916 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1917 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1918 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1920 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1921 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1922 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1929FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1934FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1938void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1943void FExtModuleOp::getAsmBlockArgumentNames(
1948StringAttr FExtModuleOp::getExtModuleNameAttr() {
1949 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1951 return getNameAttr();
1954StringRef FExtModuleOp::getExtModuleName() {
1955 if (
auto defname = getDefname(); defname && !defname->empty())
1960void FIntModuleOp::getAsmBlockArgumentNames(
1965void FMemModuleOp::getAsmBlockArgumentNames(
1970ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1972ArrayAttr FModuleOp::getParameters() {
return {}; }
1974Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1976ConventionAttr FIntModuleOp::getConventionAttr() {
1977 return ConventionAttr::get(getContext(), getConvention());
1980Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1982ConventionAttr FMemModuleOp::getConventionAttr() {
1983 return ConventionAttr::get(getContext(), getConvention());
1991 ClassLike classOp, ClassType type,
1992 function_ref<InFlightDiagnostic()> emitError) {
1994 auto name = type.getNameAttr().getAttr();
1995 auto expectedName = classOp.getModuleNameAttr();
1996 if (name != expectedName)
1997 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2000 auto elements = type.getElements();
2002 auto expectedNumElements = classOp.getNumPorts();
2004 return emitError() <<
"has wrong number of ports, got " <<
numElements
2005 <<
", expected " << expectedNumElements;
2007 auto portNames = classOp.getPortNames();
2008 auto portDirections = classOp.getPortDirections();
2009 auto portTypes = classOp.getPortTypes();
2012 auto element = elements[i];
2014 auto name = element.name;
2015 auto expectedName = portNames[i];
2016 if (name != expectedName)
2017 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2018 <<
", expected " << expectedName;
2020 auto direction = element.direction;
2021 auto expectedDirection =
Direction(portDirections[i]);
2022 if (direction != expectedDirection)
2023 return emitError() <<
"port " << name <<
" has wrong direction, got "
2027 auto type = element.type;
2028 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2029 if (type != expectedType)
2030 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2031 <<
", expected " << expectedType;
2038 auto n = classOp.getNumPorts();
2039 SmallVector<ClassElement> elements;
2040 elements.reserve(n);
2041 for (
size_t i = 0; i < n; ++i)
2042 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2043 classOp.getPortDirection(i)});
2044 auto name = FlatSymbolRefAttr::get(classOp.getModuleNameAttr());
2045 return ClassType::get(name, elements);
2048template <
typename OpTy>
2050 bool hasSSAIdentifiers) {
2051 auto *
context = result.getContext();
2052 auto &builder = parser.getBuilder();
2053 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2057 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2060 StringAttr nameAttr;
2061 if (parser.parseSymbolName(nameAttr))
2063 properties.setSymName(nameAttr);
2066 SmallVector<OpAsmParser::Argument> entryArgs;
2067 SmallVector<Direction, 4> portDirections;
2068 SmallVector<Attribute, 4> portNames;
2069 SmallVector<Attribute, 4> portTypes;
2070 SmallVector<Attribute, 4> portAnnotations;
2071 SmallVector<Attribute, 4> portSyms;
2072 SmallVector<Attribute, 4> portLocs;
2073 SmallVector<Attribute, 4> domains;
2076 entryArgs, portDirections, portNames, portTypes,
2077 portAnnotations, portSyms, portLocs, domains))
2081 for (
auto annos : portAnnotations)
2082 if (!cast<ArrayAttr>(annos).empty())
2086 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2089 assert(portNames.size() == portTypes.size());
2095 properties.setPortDirections(
2099 properties.setPortNames(builder.getArrayAttr(portNames));
2102 properties.setPortTypes(builder.getArrayAttr(portTypes));
2105 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2106 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2109 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2115 auto *bodyRegion = result.addRegion();
2117 if (hasSSAIdentifiers) {
2118 if (parser.parseRegion(*bodyRegion, entryArgs))
2120 if (bodyRegion->empty())
2121 bodyRegion->push_back(
new Block());
2127template <
typename ClassTy>
2132 StringRef visibilityAttrName =
2133 mlir::SymbolOpInterface::getDefaultVisibilityAttrName();
2134 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2135 p << visibility.getValue() <<
' ';
2138 p.printSymbolName(cast<mlir::SymbolOpInterface>(op.getOperation()).getName());
2142 Region ®ion = op->getRegion(0);
2143 Block *body =
nullptr;
2144 if (!region.empty())
2145 body = ®ion.front();
2148 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2149 {}, op.getPortSymbols(), op.getPortLocations(), {});
2152 SmallVector<StringRef, 8> omittedAttrs = {
2153 ClassTy::getSymNameAttrName(op->getName()),
2164 if (!needPortNamesAttr)
2165 omittedAttrs.push_back(
"portNames");
2167 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2170 if (!region.empty()) {
2172 auto printEntryBlockArgs =
false;
2173 auto printBlockTerminators =
false;
2174 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2182void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2183 ArrayRef<PortInfo> ports) {
2186 [](
const auto &port) {
return port.annotations.empty(); }) &&
2187 "class ports may not have annotations");
2189 buildClass<ClassOp>(builder, result, name, ports);
2192 auto *bodyRegion = result.regions[0].get();
2194 bodyRegion->push_back(body);
2197 for (
auto &elt : ports)
2198 body->addArgument(elt.type, elt.loc);
2201void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2202 ::mlir::OperationState &odsState, Twine name,
2203 mlir::ArrayRef<mlir::StringRef> fieldNames,
2204 mlir::ArrayRef<mlir::Type> fieldTypes) {
2206 SmallVector<PortInfo, 10> ports;
2207 ports.reserve(fieldNames.size() * 2);
2208 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2209 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2211 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2214 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2216 auto &body = odsState.regions[0]->getBlocks().front();
2217 auto prevLoc = odsBuilder.saveInsertionPoint();
2218 odsBuilder.setInsertionPointToEnd(&body);
2219 auto args = body.getArguments();
2220 auto loc = odsState.location;
2221 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2222 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2224 odsBuilder.restoreInsertionPoint(prevLoc);
2226void ClassOp::print(OpAsmPrinter &p) {
2227 printClassLike<ClassOp>(p, cast<ClassLike>(getOperation()));
2230ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2231 auto hasSSAIdentifiers =
true;
2232 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2235LogicalResult ClassOp::verify() {
2237 auto type = operand.getType();
2238 if (!isa<PropertyType>(type)) {
2239 emitOpError(
"ports on a class must be properties");
2248ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2252void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2257SmallVector<PortInfo> ClassOp::getPorts() {
2258 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2261void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2262 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2266void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2267 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2270Convention ClassOp::getConvention() {
return Convention::Internal; }
2272ConventionAttr ClassOp::getConventionAttr() {
2273 return ConventionAttr::get(getContext(), getConvention());
2276ArrayAttr ClassOp::getParameters() {
return {}; }
2278ArrayAttr ClassOp::getPortAnnotationsAttr() {
2279 return ArrayAttr::get(getContext(), {});
2282ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2284void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2285 llvm_unreachable(
"classes do not support annotations");
2288ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2290ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2292SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2293 return ::getPortListImpl(*
this);
2297 return ::getPortImpl(*
this, idx);
2300BlockArgument ClassOp::getArgument(
size_t portNumber) {
2304bool ClassOp::canDiscardOnUseEmpty() {
2315void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2316 StringAttr name, ArrayRef<PortInfo> ports) {
2319 [](
const auto &port) {
return port.annotations.empty(); }) &&
2320 "class ports may not have annotations");
2321 buildClass<ExtClassOp>(builder, result, name, ports);
2324void ExtClassOp::print(OpAsmPrinter &p) {
2325 printClassLike<ExtClassOp>(p, cast<ClassLike>(getOperation()));
2328ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2329 auto hasSSAIdentifiers =
false;
2330 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2334ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2338void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2343SmallVector<PortInfo> ExtClassOp::getPorts() {
2344 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2347void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2348 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2351void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2352 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2355Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2357ConventionAttr ExtClassOp::getConventionAttr() {
2358 return ConventionAttr::get(getContext(), getConvention());
2361ArrayAttr ExtClassOp::getLayersAttr() {
2362 return ArrayAttr::get(getContext(), {});
2365ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2367ArrayAttr ExtClassOp::getParameters() {
return {}; }
2369ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2370 return ArrayAttr::get(getContext(), {});
2373ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2375void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2376 llvm_unreachable(
"classes do not support annotations");
2379SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2380 return ::getPortListImpl(*
this);
2384 return ::getPortImpl(*
this, idx);
2387bool ExtClassOp::canDiscardOnUseEmpty() {
2398void InstanceOp::build(
2399 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2400 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2401 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2402 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2403 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2404 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2405 build(builder, result, resultTypes, moduleName, name, nameKind,
2406 portDirections, portNames, domainInfo, annotations, portAnnotations,
2407 layers, lowerToBind, doNotPrint,
2408 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2411void InstanceOp::build(
2412 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2413 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2414 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2415 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2416 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2417 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2418 result.addTypes(resultTypes);
2419 result.getOrAddProperties<Properties>().setModuleName(
2420 SymbolRefAttr::get(builder.getContext(), moduleName));
2421 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2422 result.getOrAddProperties<Properties>().setPortDirections(
2424 result.getOrAddProperties<Properties>().setPortNames(
2425 builder.getArrayAttr(portNames));
2427 if (domainInfo.empty()) {
2428 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2429 builder.getArrayAttr({}));
2430 result.getOrAddProperties<Properties>().setDomainInfo(
2431 builder.getArrayAttr(domainInfoVec));
2433 assert(domainInfo.size() == resultTypes.size());
2434 result.getOrAddProperties<Properties>().setDomainInfo(
2435 builder.getArrayAttr(domainInfo));
2438 result.getOrAddProperties<Properties>().setAnnotations(
2439 builder.getArrayAttr(annotations));
2440 result.getOrAddProperties<Properties>().setLayers(
2441 builder.getArrayAttr(layers));
2443 result.getOrAddProperties<Properties>().setLowerToBind(
2444 builder.getUnitAttr());
2446 result.getOrAddProperties<Properties>().setDoNotPrint(
2447 builder.getUnitAttr());
2449 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2451 result.getOrAddProperties<Properties>().setNameKind(
2452 NameKindEnumAttr::get(builder.getContext(), nameKind));
2454 if (portAnnotations.empty()) {
2455 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2456 builder.getArrayAttr({}));
2457 result.getOrAddProperties<Properties>().setPortAnnotations(
2458 builder.getArrayAttr(portAnnotationsVec));
2460 assert(portAnnotations.size() == resultTypes.size());
2461 result.getOrAddProperties<Properties>().setPortAnnotations(
2462 builder.getArrayAttr(portAnnotations));
2466void InstanceOp::build(OpBuilder &builder, OperationState &result,
2467 FModuleLike module, StringRef name,
2468 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2469 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2470 bool doNotPrint, hw::InnerSymAttr innerSym) {
2473 SmallVector<Type> resultTypes;
2474 resultTypes.reserve(module.getNumPorts());
2476 module.getPortTypes(), std::back_inserter(resultTypes),
2477 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2482 ArrayAttr portAnnotationsAttr;
2483 if (portAnnotations.empty()) {
2484 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2485 resultTypes.size(), builder.getArrayAttr({})));
2487 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2489 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2490 if (domainInfoAttr.empty()) {
2491 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2492 resultTypes.size(), builder.getArrayAttr({})));
2496 builder, result, resultTypes,
2497 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2498 builder.getStringAttr(name),
2499 NameKindEnumAttr::get(builder.getContext(), nameKind),
2500 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2501 builder.getArrayAttr(annotations), portAnnotationsAttr,
2502 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2503 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2506void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2507 ArrayRef<PortInfo> ports, StringRef moduleName,
2508 StringRef name, NameKindEnum nameKind,
2509 ArrayRef<Attribute> annotations,
2510 ArrayRef<Attribute> layers,
bool lowerToBind,
2511 bool doNotPrint, hw::InnerSymAttr innerSym) {
2513 SmallVector<Type> newResultTypes;
2514 SmallVector<Direction> newPortDirections;
2515 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2516 newResultTypes.reserve(ports.size());
2517 newPortDirections.reserve(ports.size());
2518 newPortNames.reserve(ports.size());
2519 newPortAnnotations.reserve(ports.size());
2520 newDomainInfo.reserve(ports.size());
2522 for (
auto &p : ports) {
2523 newResultTypes.push_back(p.type);
2524 newPortDirections.push_back(p.direction);
2525 newPortNames.push_back(p.name);
2526 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2528 newDomainInfo.push_back(p.domains);
2530 newDomainInfo.push_back(builder.getArrayAttr({}));
2533 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2534 newPortDirections, newPortNames, newDomainInfo, annotations,
2535 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2538LogicalResult InstanceOp::verify() {
2541 SmallVector<SymbolRefAttr> missingLayers;
2542 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2544 missingLayers.push_back(layer);
2546 if (missingLayers.empty())
2550 emitOpError(
"ambient layers are insufficient to instantiate module");
2551 auto ¬e = diag.attachNote();
2552 note <<
"missing layer requirements: ";
2553 interleaveComma(missingLayers, note);
2558 Operation *op1, Operation *op2,
2559 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2561 size_t n = insertions.size();
2562 size_t inserted = 0;
2563 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2564 while (inserted < n) {
2565 auto &[index, portInfo] = insertions[inserted];
2570 auto r1 = op1->getResult(i);
2571 auto r2 = op2->getResult(i + inserted);
2572 r1.replaceAllUsesWith(r2);
2577 const llvm::BitVector &erasures) {
2580 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2581 auto r1 = op1->getResult(i);
2583 assert(r1.use_empty() &&
"removed instance port has uses");
2587 auto r2 = op2->getResult(i - erased);
2588 r1.replaceAllUsesWith(r2);
2593InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2594 assert(erasures.size() >= getNumResults() &&
2595 "erasures is not at least as large as getNumResults()");
2597 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2598 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2599 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2601 SmallVector<Attribute> newPortNames =
2603 SmallVector<Attribute> newPortAnnotations =
2605 ArrayAttr newDomainInfo =
2609 OpBuilder builder(*
this);
2610 auto clone = InstanceOp::create(
2611 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2612 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2613 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2614 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2616 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2617 clone->setAttr(
"output_file", outputFile);
2622FInstanceLike InstanceOp::cloneWithErasedPortsAndReplaceUses(
2623 const llvm::BitVector &erasures) {
2629ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2630 assert(portIdx < getNumResults() &&
2631 "index should be smaller than result number");
2632 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2635void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2636 assert(annotations.size() == getNumResults() &&
2637 "number of annotations is not equal to result number");
2638 (*this)->setAttr(
"portAnnotations",
2639 ArrayAttr::get(getContext(), annotations));
2642FInstanceLike InstanceOp::cloneWithInsertedPorts(
2643 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2647 auto oldPortCount = getNumResults();
2648 auto numInsertions = insertions.size();
2649 auto newPortCount = oldPortCount + numInsertions;
2651 SmallVector<Direction> newPortDirections;
2652 SmallVector<Attribute> newPortNames;
2653 SmallVector<Type> newPortTypes;
2654 SmallVector<Attribute> newPortAnnos;
2655 SmallVector<Attribute> newDomainInfo;
2657 newPortDirections.reserve(newPortCount);
2658 newPortNames.reserve(newPortCount);
2659 newPortTypes.reserve(newPortCount);
2660 newPortAnnos.reserve(newPortCount);
2661 newDomainInfo.reserve(newPortCount);
2667 SmallVector<unsigned> indexMap(oldPortCount);
2668 size_t inserted = 0;
2669 for (
size_t i = 0; i < oldPortCount; ++i) {
2670 while (inserted < numInsertions && insertions[inserted].first <= i)
2672 indexMap[i] = i + inserted;
2677 for (
size_t i = 0; i < oldPortCount; ++i) {
2678 while (inserted < numInsertions) {
2679 auto &[index,
info] = insertions[inserted];
2685 newPortDirections.push_back(
info.direction);
2686 newPortNames.push_back(
info.name);
2687 newPortTypes.push_back(
info.type);
2688 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2689 newDomainInfo.push_back(domains);
2693 newPortDirections.push_back(getPortDirection(i));
2694 newPortNames.push_back(getPortNameAttr(i));
2695 newPortTypes.push_back(getType(i));
2696 newPortAnnos.push_back(getPortAnnotation(i));
2699 newDomainInfo.push_back(domains);
2702 while (inserted < numInsertions) {
2703 auto &[index,
info] = insertions[inserted];
2706 newPortDirections.push_back(
info.direction);
2707 newPortNames.push_back(
info.name);
2708 newPortTypes.push_back(
info.type);
2709 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2710 newDomainInfo.push_back(domains);
2714 OpBuilder builder(*
this);
2715 auto clone = InstanceOp::create(
2716 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2717 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2718 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2719 getDoNotPrint(), getInnerSymAttr());
2721 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2722 clone->setAttr(
"output_file", outputFile);
2727FInstanceLike InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2728 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2729 auto clone = cloneWithInsertedPorts(insertions);
2734LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2736 getModuleNameAttr());
2739StringRef InstanceOp::getInstanceName() {
return getName(); }
2741StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2743void InstanceOp::print(OpAsmPrinter &p) {
2746 p.printKeywordOrString(
getName());
2747 if (
auto attr = getInnerSymAttr()) {
2749 p.printSymbolName(attr.getSymName());
2751 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2752 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2755 SmallVector<StringRef, 10> omittedAttrs = {
2756 "moduleName",
"name",
"portDirections",
2757 "portNames",
"portTypes",
"portAnnotations",
2758 "inner_sym",
"nameKind",
"domainInfo"};
2759 if (getAnnotations().
empty())
2760 omittedAttrs.push_back(
"annotations");
2761 if (getLayers().
empty())
2762 omittedAttrs.push_back(
"layers");
2763 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2767 p.printSymbolName(getModuleName());
2770 SmallVector<Attribute> portTypes;
2771 portTypes.reserve(getNumResults());
2772 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2776 getPortNames().getValue(), portTypes,
2777 getPortAnnotations().getValue(), {}, {},
2778 getDomainInfo().getValue());
2781ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2782 auto *
context = parser.getContext();
2783 auto &properties = result.getOrAddProperties<Properties>();
2786 hw::InnerSymAttr innerSymAttr;
2787 FlatSymbolRefAttr moduleName;
2788 SmallVector<OpAsmParser::Argument> entryArgs;
2789 SmallVector<Direction, 4> portDirections;
2790 SmallVector<Attribute, 4> portNames;
2791 SmallVector<Attribute, 4> portTypes;
2792 SmallVector<Attribute, 4> portAnnotations;
2793 SmallVector<Attribute, 4> portSyms;
2794 SmallVector<Attribute, 4> portLocs;
2795 SmallVector<Attribute, 4> domains;
2796 NameKindEnumAttr nameKind;
2798 if (parser.parseKeywordOrString(&name))
2800 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2801 if (parser.parseCustomAttributeWithFallback(
2802 innerSymAttr, ::mlir::Type{},
2804 result.attributes)) {
2805 return ::mlir::failure();
2809 parser.parseOptionalAttrDict(result.attributes) ||
2810 parser.parseAttribute(moduleName) ||
2813 entryArgs, portDirections, portNames, portTypes,
2814 portAnnotations, portSyms, portLocs, domains))
2820 properties.setModuleName(moduleName);
2821 properties.setName(StringAttr::get(
context, name));
2822 properties.setNameKind(nameKind);
2823 properties.setPortDirections(
2825 properties.setPortNames(ArrayAttr::get(
context, portNames));
2826 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2830 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2831 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2834 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2837 result.types.reserve(portTypes.size());
2839 portTypes, std::back_inserter(result.types),
2840 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2845void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2850 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2851 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2855std::optional<size_t> InstanceOp::getTargetResultIndex() {
2857 return std::nullopt;
2864void InstanceChoiceOp::build(
2865 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2866 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2867 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2868 ArrayRef<Attribute> portAnnotations, StringAttr innerSym,
2869 FlatSymbolRefAttr instanceMacro) {
2871 SmallVector<Type> resultTypes;
2872 for (Attribute portType : defaultModule.getPortTypes())
2873 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2876 ArrayAttr portAnnotationsAttr;
2877 if (portAnnotations.empty()) {
2878 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2879 resultTypes.size(), builder.getArrayAttr({})));
2881 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2885 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2886 if (domainInfoAttr.empty()) {
2887 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2888 resultTypes.size(), builder.getArrayAttr({})));
2892 SmallVector<Attribute> moduleNames, caseNames;
2893 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2894 for (
auto [caseOption, caseModule] : cases) {
2895 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2896 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2897 {SymbolRefAttr::get(caseOption)}));
2898 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2901 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2902 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2903 NameKindEnumAttr::get(builder.getContext(), nameKind),
2904 defaultModule.getPortDirectionsAttr(),
2905 defaultModule.getPortNamesAttr(), domainInfoAttr,
2906 builder.getArrayAttr(annotations), portAnnotationsAttr,
2907 defaultModule.getLayersAttr(),
2908 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr(),
2912void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2913 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2914 ArrayAttr caseNames, StringRef name,
2915 NameKindEnum nameKind, ArrayAttr annotations,
2916 ArrayAttr layers, hw::InnerSymAttr innerSym,
2917 FlatSymbolRefAttr instanceMacro) {
2919 SmallVector<Type> newResultTypes;
2920 SmallVector<bool> newPortDirections;
2921 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2922 newPortDirections.reserve(ports.size());
2923 newResultTypes.reserve(ports.size());
2924 newPortAnnotations.reserve(ports.size());
2925 newDomainInfo.reserve(ports.size());
2926 newPortNames.reserve(ports.size());
2927 for (
auto &p : ports) {
2928 newResultTypes.push_back(p.type);
2930 newPortDirections.push_back(p.direction == Direction::Out);
2931 newPortNames.push_back(p.name);
2932 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2934 newDomainInfo.push_back(p.domains);
2936 newDomainInfo.push_back(builder.getArrayAttr({}));
2939 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2940 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2941 builder.getArrayAttr(newDomainInfo), annotations,
2942 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2943 innerSym, instanceMacro);
2946std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2947 return std::nullopt;
2950StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2952StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2954ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2956 auto moduleNames = getModuleNamesAttr();
2957 SmallVector<Attribute> moduleNameStrings;
2958 moduleNameStrings.reserve(moduleNames.size());
2959 for (
auto moduleName : moduleNames)
2960 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2962 return ArrayAttr::get(getContext(), moduleNameStrings);
2965void InstanceChoiceOp::print(OpAsmPrinter &p) {
2968 p.printKeywordOrString(
getName());
2969 if (
auto attr = getInnerSymAttr()) {
2971 p.printSymbolName(attr.getSymName());
2973 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2974 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2977 SmallVector<StringRef, 11> omittedAttrs = {
2978 "moduleNames",
"caseNames",
"name",
2979 "portDirections",
"portNames",
"portTypes",
2980 "portAnnotations",
"inner_sym",
"nameKind",
2982 if (getAnnotations().
empty())
2983 omittedAttrs.push_back(
"annotations");
2984 if (getLayers().
empty())
2985 omittedAttrs.push_back(
"layers");
2986 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2991 auto moduleNames = getModuleNamesAttr();
2992 auto caseNames = getCaseNamesAttr();
2994 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2996 p <<
" alternatives ";
2998 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
3000 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3004 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
3005 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
3007 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
3013 SmallVector<Attribute> portTypes;
3014 portTypes.reserve(getNumResults());
3015 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
3018 getPortNames().getValue(), portTypes,
3019 getPortAnnotations().getValue(), {}, {},
3020 getDomainInfo().getValue());
3023ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3024 OperationState &result) {
3025 auto *
context = parser.getContext();
3026 auto &properties = result.getOrAddProperties<Properties>();
3029 hw::InnerSymAttr innerSymAttr;
3030 SmallVector<Attribute> moduleNames;
3031 SmallVector<Attribute> caseNames;
3032 SmallVector<OpAsmParser::Argument> entryArgs;
3033 SmallVector<Direction, 4> portDirections;
3034 SmallVector<Attribute, 4> portNames;
3035 SmallVector<Attribute, 4> portTypes;
3036 SmallVector<Attribute, 4> portAnnotations;
3037 SmallVector<Attribute, 4> portSyms;
3038 SmallVector<Attribute, 4> portLocs;
3039 SmallVector<Attribute, 4> domains;
3040 NameKindEnumAttr nameKind;
3042 if (parser.parseKeywordOrString(&name))
3044 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3045 if (parser.parseCustomAttributeWithFallback(
3046 innerSymAttr, Type{},
3048 result.attributes)) {
3053 parser.parseOptionalAttrDict(result.attributes))
3056 FlatSymbolRefAttr defaultModuleName;
3057 if (parser.parseAttribute(defaultModuleName))
3059 moduleNames.push_back(defaultModuleName);
3063 FlatSymbolRefAttr optionName;
3064 if (parser.parseKeyword(
"alternatives") ||
3065 parser.parseAttribute(optionName) || parser.parseLBrace())
3068 FlatSymbolRefAttr moduleName;
3069 StringAttr caseName;
3070 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3071 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3073 moduleNames.push_back(moduleName);
3074 caseNames.push_back(SymbolRefAttr::get(
3075 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3076 if (failed(parser.parseOptionalComma()))
3079 if (parser.parseRBrace())
3085 entryArgs, portDirections, portNames, portTypes,
3086 portAnnotations, portSyms, portLocs, domains))
3091 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3092 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3093 properties.setName(StringAttr::get(
context, name));
3094 properties.setNameKind(nameKind);
3095 properties.setPortDirections(
3097 properties.setPortNames(ArrayAttr::get(
context, portNames));
3098 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3099 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3103 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3104 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3107 result.types.reserve(portTypes.size());
3109 portTypes, std::back_inserter(result.types),
3110 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3115void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3117 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3118 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3121LogicalResult InstanceChoiceOp::verify() {
3122 if (getCaseNamesAttr().
empty())
3123 return emitOpError() <<
"must have at least one case";
3124 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3125 return emitOpError() <<
"number of referenced modules does not match the "
3126 "number of options";
3131 SmallVector<SymbolRefAttr> missingLayers;
3132 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3134 missingLayers.push_back(layer);
3136 if (missingLayers.empty())
3140 emitOpError(
"ambient layers are insufficient to instantiate module");
3141 auto ¬e = diag.attachNote();
3142 note <<
"missing layer requirements: ";
3143 interleaveComma(missingLayers, note);
3148InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3149 auto caseNames = getCaseNamesAttr();
3150 for (
auto moduleName : getModuleNamesAttr()) {
3151 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3157 auto referencedModule =
3158 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3159 if (isa<FIntModuleOp>(referencedModule))
3160 return emitOpError(
"intmodule must be instantiated with instance op, "
3161 "not via 'firrtl.instance_choice'");
3164 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3165 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3166 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3167 auto refRoot = ref.getRootReference();
3168 if (ref.getRootReference() != root)
3169 return emitOpError() <<
"case " << ref
3170 <<
" is not in the same option group as "
3173 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3174 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3176 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3177 return emitOpError() <<
"option " << refRoot
3178 <<
" does not contain option case " << ref;
3181 if (
auto instanceMacro = getInstanceMacroAttr())
3182 if (!symbolTable.lookupNearestSymbolFrom(*
this, instanceMacro))
3183 return emitOpError() <<
"instance_macro " << instanceMacro
3184 <<
" does not exist";
3190InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3191 auto caseNames = getCaseNamesAttr();
3192 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3193 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3194 if (caseSym == option.getSymName())
3195 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3197 return getDefaultTargetAttr();
3200SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3201InstanceChoiceOp::getTargetChoices() {
3202 auto caseNames = getCaseNamesAttr();
3203 auto moduleNames = getModuleNamesAttr();
3204 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3205 for (
size_t i = 0; i < caseNames.size(); ++i) {
3206 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3207 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3213FInstanceLike InstanceChoiceOp::cloneWithInsertedPorts(
3214 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3218 auto oldPortCount = getNumResults();
3219 auto numInsertions = insertions.size();
3220 auto newPortCount = oldPortCount + numInsertions;
3222 SmallVector<Direction> newPortDirections;
3223 SmallVector<Attribute> newPortNames;
3224 SmallVector<Type> newPortTypes;
3225 SmallVector<Attribute> newPortAnnos;
3226 SmallVector<Attribute> newDomainInfo;
3228 newPortDirections.reserve(newPortCount);
3229 newPortNames.reserve(newPortCount);
3230 newPortTypes.reserve(newPortCount);
3231 newPortAnnos.reserve(newPortCount);
3232 newDomainInfo.reserve(newPortCount);
3238 SmallVector<unsigned> indexMap(oldPortCount);
3239 size_t inserted = 0;
3240 for (
size_t i = 0; i < oldPortCount; ++i) {
3241 while (inserted < numInsertions && insertions[inserted].first <= i)
3243 indexMap[i] = i + inserted;
3248 for (
size_t i = 0; i < oldPortCount; ++i) {
3249 while (inserted < numInsertions) {
3250 auto &[index,
info] = insertions[inserted];
3256 newPortDirections.push_back(
info.direction);
3257 newPortNames.push_back(
info.name);
3258 newPortTypes.push_back(
info.type);
3259 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3260 newDomainInfo.push_back(domains);
3264 newPortDirections.push_back(getPortDirection(i));
3265 newPortNames.push_back(getPortNameAttr(i));
3266 newPortTypes.push_back(getType(i));
3267 newPortAnnos.push_back(getPortAnnotations()[i]);
3270 newDomainInfo.push_back(domains);
3273 while (inserted < numInsertions) {
3274 auto &[index,
info] = insertions[inserted];
3277 newPortDirections.push_back(
info.direction);
3278 newPortNames.push_back(
info.name);
3279 newPortTypes.push_back(
info.type);
3280 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3281 newDomainInfo.push_back(domains);
3285 OpBuilder builder(*
this);
3286 auto clone = InstanceChoiceOp::create(
3287 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3290 ArrayAttr::get(
context, newPortNames),
3291 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3292 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr(),
3293 getInstanceMacroAttr());
3295 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3296 clone->setAttr(
"output_file", outputFile);
3301FInstanceLike InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3302 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3303 auto clone = cloneWithInsertedPorts(insertions);
3309InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3310 assert(erasures.size() >= getNumResults() &&
3311 "erasures is not at least as large as getNumResults()");
3313 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3314 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3315 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3317 SmallVector<Attribute> newPortNames =
3319 SmallVector<Attribute> newPortAnnotations =
3321 ArrayAttr newPortDomains =
3325 OpBuilder builder(*
this);
3326 auto clone = InstanceChoiceOp::create(
3327 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3330 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3331 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3332 getLayers(), getInnerSymAttr(), getInstanceMacroAttr());
3334 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3335 clone->setAttr(
"output_file", outputFile);
3340FInstanceLike InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3341 const llvm::BitVector &erasures) {
3351ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3352 assert(portIdx < getNumResults() &&
3353 "index should be smaller than result number");
3354 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3357void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3358 assert(annotations.size() == getNumResults() &&
3359 "number of annotations is not equal to result number");
3360 (*this)->setAttr(
"portAnnotations",
3361 ArrayAttr::get(getContext(), annotations));
3365void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3366 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3369 numReadWritePorts = 0;
3371 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3372 auto portKind = getPortKind(i);
3373 if (portKind == MemOp::PortKind::Debug)
3375 else if (portKind == MemOp::PortKind::Read)
3377 else if (portKind == MemOp::PortKind::Write) {
3380 ++numReadWritePorts;
3385LogicalResult MemOp::verify() {
3389 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3395 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3396 auto portName = getPortNameAttr(i);
3401 BundleType portBundleType =
3402 type_dyn_cast<BundleType>(getResult(i).getType());
3405 if (!portNamesSet.insert(portName).second) {
3406 emitOpError() <<
"has non-unique port name " << portName;
3414 auto elt = getPortNamed(portName);
3416 emitOpError() <<
"could not get port with name " << portName;
3419 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3422 if (portKind == MemOp::PortKind::Debug &&
3423 !type_isa<RefType>(getResult(i).getType()))
3424 return emitOpError() <<
"has an invalid type on port " << portName
3425 <<
" (expected Read/Write/ReadWrite/Debug)";
3426 if (type_isa<RefType>(firrtlType) && e == 1)
3427 return emitOpError()
3428 <<
"cannot have only one port of debug type. Debug port can only "
3429 "exist alongside other read/write/read-write port";
3434 if (portKind == MemOp::PortKind::Debug) {
3435 auto resType = type_cast<RefType>(getResult(i).getType());
3436 if (!(resType && type_isa<FVectorType>(resType.getType())))
3437 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3438 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3440 auto dataTypeOption = portBundleType.getElement(
"data");
3441 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3442 dataTypeOption = portBundleType.getElement(
"wdata");
3443 if (!dataTypeOption) {
3444 emitOpError() <<
"has no data field on port " << portName
3445 <<
" (expected to see \"data\" for a read or write "
3446 "port or \"rdata\" for a read/write port)";
3449 dataType = dataTypeOption->type;
3451 if (portKind == MemOp::PortKind::Read) {
3458 emitOpError() <<
"has non-passive data type on port " << portName
3459 <<
" (memory types must be passive)";
3464 if (dataType.containsAnalog()) {
3465 emitOpError() <<
"has a data type that contains an analog type on port "
3467 <<
" (memory types cannot contain analog types)";
3475 getTypeForPort(getDepth(), dataType, portKind,
3476 dataType.isGround() ? getMaskBits() : 0);
3479 auto originalType = getResult(i).getType();
3480 if (originalType != expectedType) {
3481 StringRef portKindName;
3483 case MemOp::PortKind::Read:
3484 portKindName =
"read";
3486 case MemOp::PortKind::Write:
3487 portKindName =
"write";
3489 case MemOp::PortKind::ReadWrite:
3490 portKindName =
"readwrite";
3492 case MemOp::PortKind::Debug:
3493 portKindName =
"dbg";
3496 emitOpError() <<
"has an invalid type for port " << portName
3497 <<
" of determined kind \"" << portKindName
3498 <<
"\" (expected " << expectedType <<
", but got "
3499 << originalType <<
")";
3505 if (oldDataType && oldDataType != dataType) {
3506 emitOpError() <<
"port " << getPortNameAttr(i)
3507 <<
" has a different type than port "
3508 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3509 <<
", but got " << dataType <<
")";
3513 oldDataType = dataType;
3516 auto maskWidth = getMaskBits();
3518 auto dataWidth = getDataType().getBitWidthOrSentinel();
3519 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3520 return emitOpError(
"the mask width cannot be greater than "
3523 if (getPortAnnotations().size() != getNumResults())
3524 return emitOpError(
"the number of result annotations should be "
3525 "equal to the number of results");
3531 return std::max(1U, llvm::Log2_64_Ceil(depth));
3537 PortKind portKind,
size_t maskBits) {
3539 auto *
context = dataType.getContext();
3540 if (portKind == PortKind::Debug)
3541 return RefType::get(FVectorType::get(dataType, depth));
3547 maskType = UIntType::get(
context, maskBits);
3549 auto getId = [&](StringRef name) -> StringAttr {
3550 return StringAttr::get(
context, name);
3553 SmallVector<BundleType::BundleElement, 7> portFields;
3557 portFields.push_back({getId(
"addr"),
false, addressType});
3558 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3559 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3562 case PortKind::Read:
3563 portFields.push_back({getId(
"data"),
true, dataType});
3566 case PortKind::Write:
3567 portFields.push_back({getId(
"data"),
false, dataType});
3568 portFields.push_back({getId(
"mask"),
false, maskType});
3571 case PortKind::ReadWrite:
3572 portFields.push_back({getId(
"rdata"),
true, dataType});
3573 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3574 portFields.push_back({getId(
"wdata"),
false, dataType});
3575 portFields.push_back({getId(
"wmask"),
false, maskType});
3578 llvm::report_fatal_error(
"memory port kind not handled");
3582 return BundleType::get(
context, portFields);
3586SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3587 SmallVector<MemOp::NamedPort> result;
3589 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3591 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3598MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3600 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3604MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3606 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3610size_t MemOp::getMaskBits() {
3612 for (
auto res : getResults()) {
3613 if (type_isa<RefType>(res.getType()))
3615 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3622 if (t.name.getValue().contains(
"mask"))
3625 if (type_isa<UIntType>(mType))
3635 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3637 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3638 return type_cast<FVectorType>(refType.getType()).getElementType();
3639 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3641 StringRef dataFieldName =
"data";
3643 dataFieldName =
"rdata";
3645 return type_cast<BundleType>(firstPortType.getPassiveType())
3646 .getElementType(dataFieldName);
3649StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3650 return cast<StringAttr>(getPortNames()[resultNo]);
3654 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3657Value MemOp::getPortNamed(StringAttr name) {
3658 auto namesArray = getPortNames();
3659 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3660 if (namesArray[i] == name) {
3661 assert(i < getNumResults() &&
" names array out of sync with results");
3662 return getResult(i);
3671 size_t numReadPorts = 0;
3672 size_t numWritePorts = 0;
3673 size_t numReadWritePorts = 0;
3675 SmallVector<int32_t> writeClockIDs;
3677 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3678 auto portKind = op.getPortKind(i);
3679 if (portKind == MemOp::PortKind::Read)
3681 else if (portKind == MemOp::PortKind::Write) {
3682 for (
auto *a : op.getResult(i).getUsers()) {
3683 auto subfield = dyn_cast<SubfieldOp>(a);
3684 if (!subfield || subfield.getFieldIndex() != 2)
3686 auto clockPort = a->getResult(0);
3687 for (
auto *b : clockPort.getUsers()) {
3688 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3689 if (
connect.getDest() == clockPort) {
3692 connect.getSrc(),
true,
true,
true),
3694 if (result.second) {
3695 writeClockIDs.push_back(numWritePorts);
3697 writeClockIDs.push_back(result.first->second);
3706 ++numReadWritePorts;
3713 op.emitError(
"'firrtl.mem' should have simple type and known width");
3714 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3716 if (op->hasAttr(
"modName"))
3717 modName = op->getAttrOfType<StringAttr>(
"modName");
3719 SmallString<8> clocks;
3720 for (
auto a : writeClockIDs)
3721 clocks.
append(Twine((char)(a +
'a')).str());
3722 SmallString<32> initStr;
3727 for (
auto c : init.getFilename().getValue())
3728 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3729 (c >=
'0' && c <=
'9'))
3730 initStr.push_back(c);
3731 initStr.push_back(
'_');
3732 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3733 initStr.push_back(
'_');
3734 initStr.push_back(init.getIsInline() ?
't' :
'f');
3736 modName = StringAttr::get(
3739 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3740 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3741 numReadWritePorts, (
size_t)width, op.getDepth(),
3742 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3743 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3744 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3746 return {numReadPorts,
3751 op.getReadLatency(),
3752 op.getWriteLatency(),
3754 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3755 seq::WUW::PortOrder,
3758 op.getMaskBits() > 1,
3764void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3769 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3770 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3774std::optional<size_t> MemOp::getTargetResultIndex() {
3776 return std::nullopt;
3784 OpAsmSetValueNameFn setNameFn) {
3787 setNameFn(op.getDataRaw(), name);
3788 if (op.isForceable())
3789 setNameFn(op.getDataRef(), (name +
"_ref").str());
3792void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3796LogicalResult NodeOp::inferReturnTypes(
3797 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3798 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3799 ::mlir::PropertyRef properties, ::mlir::RegionRange regions,
3800 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3801 if (operands.empty())
3803 Adaptor adaptor(operands, attributes, properties, regions);
3804 inferredReturnTypes.push_back(adaptor.getInput().getType());
3805 if (adaptor.getForceable()) {
3807 true, adaptor.getInput().getType());
3808 if (!forceableType) {
3810 ::mlir::emitError(*location,
"cannot force a node of type ")
3811 << operands[0].getType();
3814 inferredReturnTypes.push_back(forceableType);
3819std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3821void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3825std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3827SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3828RegOp::computeDataFlow() {
3837 IntegerAttr initial) {
3842 auto intType = type_dyn_cast<IntType>(regType);
3844 return op->emitError(
3845 "'initial' value is only supported on ground-type registers");
3848 auto width = intType.getWidthOrSentinel();
3849 if (width != -1 && (
int)initial.getValue().getBitWidth() != width)
3850 return op->emitError(
"'initial' value bitwidth (")
3851 << initial.getValue().getBitWidth()
3852 <<
") doesn't match register type width (" << width <<
")";
3855 auto attrType = type_cast<IntegerType>(initial.getType());
3856 if (attrType.isSignless() || attrType.isSigned() != intType.isSigned())
3857 return op->emitError(
"'initial' value has wrong sign");
3862LogicalResult RegOp::verify() {
3866LogicalResult RegResetOp::verify() {
3867 auto reset = getResetValue();
3874 return emitError(
"type mismatch between register ")
3875 << regType <<
" and reset value " << resetType;
3880std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3882void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3891FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3892 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3894 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3896 if (!isa<FModuleLike>(op)) {
3897 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3898 <<
" is not a module";
3899 d.attachNote(op->getLoc()) <<
"target defined here";
3911SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3912 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3914 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3916 auto complain = [&] {
3917 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3918 d.attachNote(op->getLoc()) <<
"target defined here";
3922 auto module = dyn_cast<FModuleLike>(op);
3924 return complain() <<
"is not a module";
3926 auto numPorts =
module.getNumPorts();
3928 return complain() <<
"must have at least 4 ports, got " << numPorts
3932 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3933 llvm::function_ref<bool(Type)> checkType,
3934 StringRef expType) {
3935 auto name =
module.getPortNameAttr(idx);
3936 if (name != expName) {
3937 complain() <<
"port " << idx <<
" must be called \"" << expName
3938 <<
"\", got " << name <<
" instead";
3941 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3945 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3946 <<
", got " << stringify(dir) <<
" instead";
3949 if (
auto type = module.getPortType(idx); !checkType(type)) {
3950 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3951 <<
"', got " << type <<
" instead";
3957 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3958 auto isBool = [](Type type) {
3959 if (
auto uintType = dyn_cast<UIntType>(type))
3960 return uintType.getWidth() == 1;
3964 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3971 for (
unsigned i = 4; i < numPorts; ++i) {
3972 auto type =
module.getPortType(i);
3973 auto firrtlType = type_dyn_cast<FIRRTLType>(type);
3975 return complain() <<
"port " << i <<
" contains hardware types: " << type;
3985void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3989SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3990RegResetOp::computeDataFlow() {
3995std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3997LogicalResult WireOp::verify() {
3999 if (type_isa<DomainType>(getResult().getType()) && !getDomains().
empty())
4000 return emitOpError(
"of domain type must not have domain associations");
4003 auto domains = getDomains();
4004 if (!domains.size())
4017 using oldValueAndDiag = std::pair<Value, std::unique_ptr<InFlightDiagnostic>>;
4019 bool hasErrors =
false;
4020 for (
auto domain : domains) {
4021 auto domainType = cast<DomainType>(domain.getType());
4022 auto domainName = domainType.getName();
4025 auto [it, inserted] =
4026 domainInfo.try_emplace(domainName, std::make_pair(domain,
nullptr));
4033 auto &[value, diag] = it->second;
4039 diag = std::make_unique<InFlightDiagnostic>(
4040 emitOpError() <<
"associated with multiple operands of '"
4041 << domainName.getValue() <<
"' kind");
4042 diag->attachNote(value.getLoc()) <<
"first domain operand here";
4047 diag->attachNote(domain.getLoc())
4048 <<
"additional colliding domain operand here";
4060 for (
auto &[_, diag] : domainInfo.values())
4066LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4067 if (
auto refType = type_dyn_cast<RefType>(getType(0)))
4069 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4070 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4072 if (
auto domainType = type_dyn_cast<DomainType>(getType(0)))
4073 return domainType.verifySymbolUses(getOperation(), symbolTable);
4082LogicalResult ContractOp::verify() {
4083 if (getBody().getArgumentTypes() != getInputs().getType())
4084 return emitOpError(
"result types and region argument types must match");
4093OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4094 auto caseMacro = getCaseMacroAttr();
4099 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4100 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4102 return emitOpError(
"case_macro references an undefined symbol: ")
4105 if (!isa<sv::MacroDeclOp>(refOp))
4106 return emitOpError(
"case_macro must reference a macro declaration");
4115void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4117 build(builder, state, klass.getInstanceType(),
4118 StringAttr::get(builder.getContext(), name));
4121LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4122 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4123 auto classType = getType();
4124 auto className = classType.getNameAttr();
4127 auto classOp = dyn_cast_or_null<ClassLike>(
4128 symbolTable.lookupSymbolIn(circuitOp, className));
4130 return emitOpError() <<
"references unknown class " << className;
4133 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4139StringAttr ObjectOp::getClassNameAttr() {
4140 return getType().getNameAttr().getAttr();
4143StringRef ObjectOp::getClassName() {
return getType().getName(); }
4145ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4146 auto symRef = getType().getNameAttr();
4147 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4150Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4151 return getReferencedClass(symtbl);
4154StringRef ObjectOp::getInstanceName() {
return getName(); }
4156StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4158StringAttr ObjectOp::getReferencedModuleNameAttr() {
4159 return getClassNameAttr();
4162void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4163 setNameFn(getResult(),
getName());
4170LogicalResult AttachOp::verify() {
4172 std::optional<int32_t> commonWidth;
4173 for (
auto operand : getOperands()) {
4174 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4178 commonWidth = thisWidth;
4181 if (commonWidth != thisWidth)
4182 return emitOpError(
"is inavlid as not all known operand widths match");
4189 Value dst = connect->getOperand(0);
4190 Value src = connect->getOperand(1);
4199 if (isa<PropertyType>(src.getType()) ||
4203 auto diag = emitError(connect->getLoc());
4204 diag <<
"connect has invalid flow: the source expression ";
4206 diag <<
"\"" << srcName <<
"\" ";
4207 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4208 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4216 auto diag = emitError(connect->getLoc());
4217 diag <<
"connect has invalid flow: the destination expression ";
4219 diag <<
"\"" << dstName <<
"\" ";
4220 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4221 return diag.attachNote(dstRef.getLoc())
4222 <<
"the destination was defined here";
4231 bool outerTypeIsConst =
false) {
4232 auto typeIsConst = outerTypeIsConst || type.
isConst();
4237 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4238 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4239 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4243 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4255 auto dest = connect.getDest();
4256 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4257 auto src = connect.getSrc();
4258 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4259 if (!destType || !srcType)
4262 auto destRefinedType = destType;
4263 auto srcRefinedType = srcType;
4268 auto findFieldDeclarationRefiningFieldType =
4270 while (
auto *definingOp = value.getDefiningOp()) {
4271 bool shouldContinue =
true;
4272 TypeSwitch<Operation *>(definingOp)
4273 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4274 .Case<SubaccessOp>([&](SubaccessOp op) {
4278 .getElementTypePreservingConst()
4280 originalFieldType = originalFieldType.getConstType(
true);
4281 value = op.getInput();
4283 .Default([&](Operation *) { shouldContinue =
false; });
4284 if (!shouldContinue)
4290 auto destDeclaration =
4291 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4292 auto srcDeclaration =
4293 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4295 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4296 Value declaration) -> LogicalResult {
4297 auto *declarationBlock = declaration.getParentBlock();
4298 auto *block = connect->getBlock();
4299 while (block && block != declarationBlock) {
4300 auto *parentOp = block->getParentOp();
4302 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4303 whenOp && !whenOp.getCondition().getType().isConst()) {
4305 return connect.emitOpError()
4306 <<
"assignment to 'const' type " << type
4307 <<
" is dependent on a non-'const' condition";
4308 return connect->emitOpError()
4309 <<
"assignment to nested 'const' member of type " << type
4310 <<
" is dependent on a non-'const' condition";
4313 block = parentOp->getBlock();
4318 auto emitSubaccessError = [&] {
4319 return connect.emitError(
4320 "assignment to non-'const' subaccess of 'const' type is disallowed");
4326 if (destType != destRefinedType)
4327 return emitSubaccessError();
4329 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4334 if (srcRefinedType.containsConst() &&
4337 if (srcType != srcRefinedType)
4338 return emitSubaccessError();
4339 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4356 auto dest = connect.getDest();
4357 for (
auto *user : dest.getUsers()) {
4358 if (
auto c = dyn_cast<FConnectLike>(user);
4359 c && c.getDest() == dest && c != connect) {
4360 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4362 diag.attachNote(c->getLoc()) <<
"other driver is here";
4369LogicalResult ConnectOp::verify() {
4370 auto dstType = getDest().getType();
4371 auto srcType = getSrc().getType();
4372 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4373 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4374 if (!dstBaseType || !srcBaseType) {
4375 if (dstType != srcType)
4376 return emitError(
"may not connect different non-base types");
4379 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4380 return emitError(
"analog types may not be connected");
4384 return emitError(
"type mismatch between destination ")
4385 << dstBaseType <<
" and source " << srcBaseType;
4390 return emitError(
"destination ")
4391 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4404LogicalResult MatchingConnectOp::verify() {
4405 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4406 auto baseType = type_cast<FIRRTLBaseType>(type);
4409 if (baseType && baseType.containsAnalog())
4410 return emitError(
"analog types may not be connected");
4415 "`SameAnonTypeOperands` trait should have already rejected "
4416 "structurally non-equivalent types");
4429LogicalResult RefDefineOp::verify() {
4436 if (
auto *op = getDest().getDefiningOp()) {
4438 if (isa<RefSubOp>(op))
4440 "destination reference cannot be a sub-element of a reference");
4441 if (isa<RefCastOp>(op))
4443 "destination reference cannot be a cast of another reference");
4451 SmallVector<SymbolRefAttr> missingLayers;
4454 "has more layer requirements than destination",
4455 "additional layers required");
4458LogicalResult PropAssignOp::verify() {
4468LogicalResult PropertyAssertOp::verify() {
4471 if (
auto *defOp = getCondition().getDefiningOp())
4472 if (
auto boolConst = dyn_cast<BoolConstantOp>(defOp))
4473 if (!boolConst.getValue())
4474 return emitOpError(
"property assertion is statically false");
4479 auto domainType = dyn_cast<DomainType>(value.getType());
4484 return domainType.getName();
4487LogicalResult DomainDefineOp::verify() {
4494 auto dst = getDest();
4495 auto src = getSrc();
4503 if (
auto *srcDefOp = src.getDefiningOp())
4504 if (isa<WireOp>(srcDefOp))
4506 if (
auto *dstDefOp = dst.getDefiningOp())
4507 if (isa<WireOp>(dstDefOp))
4512 return emitError(
"could not determine domain-type of destination");
4516 return emitError(
"could not determine domain-type of source");
4518 if (dstDomain != srcDomain) {
4519 auto diag = emitError()
4520 <<
"source domain type " << srcDomain
4521 <<
" does not match destination domain type " << dstDomain;
4528void WhenOp::createElseRegion() {
4529 assert(!hasElseRegion() &&
"already has an else region");
4530 getElseRegion().push_back(
new Block());
4533void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4534 bool withElseRegion, std::function<
void()> thenCtor,
4535 std::function<
void()> elseCtor) {
4536 OpBuilder::InsertionGuard guard(builder);
4537 result.addOperands(condition);
4540 builder.createBlock(result.addRegion());
4545 Region *elseRegion = result.addRegion();
4546 if (withElseRegion) {
4547 builder.createBlock(elseRegion);
4557LogicalResult MatchOp::verify() {
4558 FEnumType type = getInput().getType();
4561 auto numCases = getTags().size();
4562 auto numRegions = getNumRegions();
4563 if (numRegions != numCases)
4564 return emitOpError(
"expected ")
4565 << numRegions <<
" tags but got " << numCases;
4567 auto numTags = type.getNumElements();
4569 SmallDenseSet<int64_t> seen;
4570 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4571 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4574 if (region.getNumArguments() != 1)
4575 return emitOpError(
"region should have exactly one argument");
4578 if (tagIndex >= numTags)
4579 return emitOpError(
"the tag index ")
4580 << tagIndex <<
" is out of the range of valid tags in " << type;
4583 auto [it, inserted] = seen.insert(tagIndex);
4585 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4586 <<
" is matched more than once";
4589 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4590 auto regionType = region.getArgument(0).getType();
4591 if (regionType != expectedType)
4592 return emitOpError(
"region type ")
4593 << regionType <<
" does not match the expected type "
4598 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4599 if (!seen.contains(i))
4600 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4605void MatchOp::print(OpAsmPrinter &p) {
4606 auto input = getInput();
4607 FEnumType type = input.getType();
4608 auto regions = getRegions();
4609 p <<
" " << input <<
" : " << type;
4610 SmallVector<StringRef> elided = {
"tags"};
4611 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4614 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4617 p.printKeywordOrString(
4618 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4620 p.printRegionArgument(region.front().getArgument(0), {},
4623 p.printRegion(region,
false);
4630ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4631 auto *
context = parser.getContext();
4632 auto &properties = result.getOrAddProperties<Properties>();
4633 OpAsmParser::UnresolvedOperand input;
4634 if (parser.parseOperand(input) || parser.parseColon())
4637 auto loc = parser.getCurrentLocation();
4639 if (parser.parseType(type))
4641 auto enumType = type_dyn_cast<FEnumType>(type);
4643 return parser.emitError(loc,
"expected enumeration type but got") << type;
4645 if (parser.resolveOperand(input, type, result.operands) ||
4646 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4647 parser.parseLBrace())
4650 auto i32Type = IntegerType::get(
context, 32);
4651 SmallVector<Attribute> tags;
4654 if (failed(parser.parseOptionalKeyword(
"case")))
4658 auto nameLoc = parser.getCurrentLocation();
4660 OpAsmParser::Argument arg;
4661 auto *region = result.addRegion();
4662 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4663 parser.parseArgument(arg) || parser.parseRParen())
4667 auto index = enumType.getElementIndex(name);
4669 return parser.emitError(nameLoc,
"the tag \"")
4670 << name <<
"\" is not a member of the enumeration " << enumType;
4671 tags.push_back(IntegerAttr::get(i32Type, *index));
4674 arg.type = enumType.getElementTypePreservingConst(*index);
4675 if (parser.parseRegion(*region, arg))
4678 properties.setTags(ArrayAttr::get(
context, tags));
4680 return parser.parseRBrace();
4683void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4685 MutableArrayRef<std::unique_ptr<Region>> regions) {
4686 auto &properties = result.getOrAddProperties<Properties>();
4687 result.addOperands(input);
4688 properties.setTags(tags);
4689 result.addRegions(regions);
4698 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4699 bool visitInvalidExpr(Operation *op) {
return false; }
4700 bool visitUnhandledExpr(Operation *op) {
return true; }
4706void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4709 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4710 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4711 auto width = ty.getWidthOrSentinel();
4715 name = (Twine(base) + Twine(width)).str();
4716 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4717 auto width = ty.getWidthOrSentinel();
4719 name =
"invalid_analog";
4721 name = (
"invalid_analog" + Twine(width)).str();
4722 }
else if (type_isa<AsyncResetType>(getType()))
4723 name =
"invalid_asyncreset";
4724 else if (type_isa<ResetType>(getType()))
4725 name =
"invalid_reset";
4726 else if (type_isa<ClockType>(getType()))
4727 name =
"invalid_clock";
4731 setNameFn(getResult(), name);
4734void ConstantOp::print(OpAsmPrinter &p) {
4736 p.printAttributeWithoutType(getValueAttr());
4738 p.printType(getType());
4739 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4742ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4743 auto &properties = result.getOrAddProperties<Properties>();
4746 auto loc = parser.getCurrentLocation();
4747 auto valueResult = parser.parseOptionalInteger(value);
4748 if (!valueResult.has_value())
4749 return parser.emitError(loc,
"expected integer value");
4753 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4754 parser.parseOptionalAttrDict(result.attributes))
4756 result.addTypes(resultType);
4762 if (width > value.getBitWidth()) {
4766 value = value.sext(width);
4767 }
else if (width < value.getBitWidth()) {
4770 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4771 : value.getActiveBits();
4772 if (width < neededBits)
4773 return parser.emitError(loc,
"constant out of range for result type ")
4775 value = value.trunc(width);
4779 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4781 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4782 properties.setValue(valueAttr);
4786LogicalResult ConstantOp::verify() {
4790 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4792 "firrtl.constant attribute bitwidth doesn't match return type");
4795 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4796 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4797 return emitError(
"firrtl.constant attribute has wrong sign");
4804void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4805 const APInt &value) {
4808 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4809 "incorrect attribute bitwidth for firrtl.constant");
4812 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4813 return build(builder, result, type, attr);
4818void ConstantOp::build(OpBuilder &builder, OperationState &result,
4819 const APSInt &value) {
4820 auto attr = IntegerAttr::get(builder.getContext(), value);
4822 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4823 return build(builder, result, type, attr);
4826void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4833 SmallString<32> specialNameBuffer;
4834 llvm::raw_svector_ostream specialName(specialNameBuffer);
4836 getValue().print(specialName, intTy.
isSigned());
4838 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4841 specialName << width;
4842 setNameFn(getResult(), specialName.str());
4845void SpecialConstantOp::print(OpAsmPrinter &p) {
4848 p << static_cast<unsigned>(getValue());
4850 p.printType(getType());
4851 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4854ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4855 OperationState &result) {
4856 auto &properties = result.getOrAddProperties<Properties>();
4860 auto loc = parser.getCurrentLocation();
4861 auto valueResult = parser.parseOptionalInteger(value);
4862 if (!valueResult.has_value())
4863 return parser.emitError(loc,
"expected integer value");
4866 if (value != 0 && value != 1)
4867 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4871 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4872 parser.parseOptionalAttrDict(result.attributes))
4874 result.addTypes(resultType);
4877 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4878 properties.setValue(valueAttr);
4882void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4883 SmallString<32> specialNameBuffer;
4884 llvm::raw_svector_ostream specialName(specialNameBuffer);
4886 specialName << static_cast<unsigned>(getValue());
4887 auto type = getType();
4888 if (type_isa<ClockType>(type)) {
4889 specialName <<
"_clock";
4890 }
else if (type_isa<ResetType>(type)) {
4891 specialName <<
"_reset";
4892 }
else if (type_isa<AsyncResetType>(type)) {
4893 specialName <<
"_asyncreset";
4895 setNameFn(getResult(), specialName.str());
4902 if (type.isGround()) {
4903 if (!isa<IntegerAttr>(attr)) {
4904 op->emitOpError(
"Ground type is not an integer attribute");
4909 auto attrlist = dyn_cast<ArrayAttr>(attr);
4911 op->emitOpError(
"expected array attribute for aggregate constant");
4914 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4915 if (array.getNumElements() != attrlist.size()) {
4916 op->emitOpError(
"array attribute (")
4917 << attrlist.size() <<
") has wrong size for vector constant ("
4918 << array.getNumElements() <<
")";
4921 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4925 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4926 if (bundle.getNumElements() != attrlist.size()) {
4927 op->emitOpError(
"array attribute (")
4928 << attrlist.size() <<
") has wrong size for bundle constant ("
4929 << bundle.getNumElements() <<
")";
4932 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4933 if (bundle.getElement(i).isFlip) {
4934 op->emitOpError(
"Cannot have constant bundle type with flip");
4942 op->emitOpError(
"Unknown aggregate type");
4946LogicalResult AggregateConstantOp::verify() {
4952Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4954 Attribute value = getFields();
4955 while (fieldID != 0) {
4956 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4957 auto index = bundle.getIndexForFieldID(fieldID);
4958 fieldID -= bundle.getFieldID(index);
4959 type = bundle.getElementType(index);
4960 value = cast<ArrayAttr>(value)[index];
4962 auto vector = type_cast<FVectorType>(type);
4963 auto index = vector.getIndexForFieldID(fieldID);
4964 fieldID -= vector.getFieldID(index);
4965 type = vector.getElementType();
4966 value = cast<ArrayAttr>(value)[index];
4972LogicalResult FIntegerConstantOp::verify() {
4973 auto i = getValueAttr();
4974 if (!i.getType().isSignedInteger())
4975 return emitOpError(
"value must be signed");
4979void FIntegerConstantOp::print(OpAsmPrinter &p) {
4981 p.printAttributeWithoutType(getValueAttr());
4982 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4985ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4986 OperationState &result) {
4987 auto *
context = parser.getContext();
4988 auto &properties = result.getOrAddProperties<Properties>();
4990 if (parser.parseInteger(value) ||
4991 parser.parseOptionalAttrDict(result.attributes))
4993 result.addTypes(FIntegerType::get(
context));
4995 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4996 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4997 properties.setValue(valueAttr);
5001ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5002 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
5005 if (parser.parseOperandList(operands) ||
5006 parser.parseOptionalAttrDict(result.attributes) ||
5007 parser.parseColonType(type))
5009 result.addTypes(type);
5011 return parser.resolveOperands(operands, type.getElementType(),
5015void ListCreateOp::print(OpAsmPrinter &p) {
5017 p.printOperands(getElements());
5018 p.printOptionalAttrDict((*this)->getAttrs());
5019 p <<
" : " << getType();
5022LogicalResult ListCreateOp::verify() {
5023 if (getElements().
empty())
5026 auto elementType = getElements().front().getType();
5027 auto listElementType = getType().getElementType();
5029 return emitOpError(
"has elements of type ")
5030 <<
elementType <<
" instead of " << listElementType;
5035LogicalResult BundleCreateOp::verify() {
5036 BundleType resultType = getType();
5037 if (resultType.getNumElements() != getFields().size())
5038 return emitOpError(
"number of fields doesn't match type");
5039 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5041 resultType.getElementTypePreservingConst(i),
5042 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5043 return emitOpError(
"type of element doesn't match bundle for field ")
5044 << resultType.getElement(i).name;
5049LogicalResult VectorCreateOp::verify() {
5050 FVectorType resultType = getType();
5051 if (resultType.getNumElements() != getFields().size())
5052 return emitOpError(
"number of fields doesn't match type");
5053 auto elemTy = resultType.getElementTypePreservingConst();
5054 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5056 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5057 return emitOpError(
"type of element doesn't match vector element");
5063UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5065 auto classType = dyn_cast<ClassType>(getType());
5069 auto className = classType.getNameAttr();
5071 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5073 return emitOpError() <<
"refers to non-existent class ("
5074 << className.getAttr() <<
")";
5077 if (!isa<ClassLike>(op))
5078 return emitOpError() <<
"refers to a non-class type ("
5079 << className.getAttr() <<
")";
5088LogicalResult FEnumCreateOp::verify() {
5089 FEnumType resultType = getResult().getType();
5090 auto elementIndex = resultType.getElementIndex(
getFieldName());
5092 return emitOpError(
"label ")
5093 <<
getFieldName() <<
" is not a member of the enumeration type "
5096 resultType.getElementTypePreservingConst(*elementIndex),
5097 getInput().getType()))
5098 return emitOpError(
"type of element doesn't match enum element");
5102void FEnumCreateOp::print(OpAsmPrinter &printer) {
5105 printer <<
'(' << getInput() <<
')';
5106 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5107 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5109 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5110 ArrayRef<Type>{getResult().getType()});
5113ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5114 auto *
context = parser.getContext();
5115 auto &properties = result.getOrAddProperties<Properties>();
5117 OpAsmParser::UnresolvedOperand input;
5118 std::string fieldName;
5119 mlir::FunctionType functionType;
5120 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5121 parser.parseOperand(input) || parser.parseRParen() ||
5122 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5123 parser.parseType(functionType))
5126 if (functionType.getNumInputs() != 1)
5127 return parser.emitError(parser.getNameLoc(),
"single input type required");
5128 if (functionType.getNumResults() != 1)
5129 return parser.emitError(parser.getNameLoc(),
"single result type required");
5131 auto inputType = functionType.getInput(0);
5132 if (parser.resolveOperand(input, inputType, result.operands))
5135 auto outputType = functionType.getResult(0);
5136 auto enumType = type_dyn_cast<FEnumType>(outputType);
5138 return parser.emitError(parser.getNameLoc(),
5139 "output must be enum type, got ")
5141 auto fieldIndex = enumType.getElementIndex(fieldName);
5143 return parser.emitError(parser.getNameLoc(),
5144 "unknown field " + fieldName +
" in enum type ")
5147 properties.setFieldIndex(
5148 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5150 result.addTypes(enumType);
5159LogicalResult IsTagOp::verify() {
5160 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5161 return emitOpError(
"element index is greater than the number of fields in "
5166void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5167 printer <<
' ' << getInput() <<
' ';
5169 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5170 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5171 printer <<
" : " << getInput().getType();
5174ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5175 auto *
context = parser.getContext();
5176 auto &properties = result.getOrAddProperties<Properties>();
5178 OpAsmParser::UnresolvedOperand input;
5179 std::string fieldName;
5181 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5182 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5183 parser.parseType(inputType))
5186 if (parser.resolveOperand(input, inputType, result.operands))
5189 auto enumType = type_dyn_cast<FEnumType>(inputType);
5191 return parser.emitError(parser.getNameLoc(),
5192 "input must be enum type, got ")
5194 auto fieldIndex = enumType.getElementIndex(fieldName);
5196 return parser.emitError(parser.getNameLoc(),
5197 "unknown field " + fieldName +
" in enum type ")
5200 properties.setFieldIndex(
5201 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5203 result.addTypes(UIntType::get(
context, 1,
false));
5208FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5209 PropertyRef properties,
5210 mlir::RegionRange regions,
5211 std::optional<Location> loc) {
5212 Adaptor adaptor(operands, attrs, properties, regions);
5213 return UIntType::get(attrs.getContext(), 1,
5214 isConst(adaptor.getInput().getType()));
5217template <
typename OpTy>
5219 auto *
context = parser.getContext();
5221 OpAsmParser::UnresolvedOperand input;
5222 std::string fieldName;
5224 if (parser.parseOperand(input) || parser.parseLSquare() ||
5225 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5226 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5227 parser.parseType(inputType))
5230 if (parser.resolveOperand(input, inputType, result.operands))
5233 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5235 return parser.emitError(parser.getNameLoc(),
5236 "input must be bundle type, got ")
5238 auto fieldIndex = bundleType.getElementIndex(fieldName);
5240 return parser.emitError(parser.getNameLoc(),
5241 "unknown field " + fieldName +
" in bundle type ")
5244 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5245 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5247 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5250 result.addTypes(type);
5255ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5256 auto *
context = parser.getContext();
5258 OpAsmParser::UnresolvedOperand input;
5259 std::string fieldName;
5261 if (parser.parseOperand(input) || parser.parseLSquare() ||
5262 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5263 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5264 parser.parseType(inputType))
5267 if (parser.resolveOperand(input, inputType, result.operands))
5270 auto enumType = type_dyn_cast<FEnumType>(inputType);
5272 return parser.emitError(parser.getNameLoc(),
5273 "input must be enum type, got ")
5275 auto fieldIndex = enumType.getElementIndex(fieldName);
5277 return parser.emitError(parser.getNameLoc(),
5278 "unknown field " + fieldName +
" in enum type ")
5281 result.getOrAddProperties<Properties>().setFieldIndex(
5282 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5284 SmallVector<Type> inferredReturnTypes;
5285 if (failed(SubtagOp::inferReturnTypes(
5286 context, result.location, result.operands,
5287 result.attributes.getDictionary(
context), result.getRawProperties(),
5288 result.regions, inferredReturnTypes)))
5290 result.addTypes(inferredReturnTypes);
5295ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5296 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5298ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5299 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5302template <
typename OpTy>
5304 printer <<
' ' << op.getInput() <<
'[';
5305 printer.printKeywordOrString(op.getFieldName());
5307 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5308 elidedAttrs.push_back(
"fieldIndex");
5309 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5310 printer <<
" : " << op.getInput().getType();
5312void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5313 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5315void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5316 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5319void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5320 printer <<
' ' << getInput() <<
'[';
5323 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5324 elidedAttrs.push_back(
"fieldIndex");
5325 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5326 printer <<
" : " << getInput().getType();
5329template <
typename OpTy>
5331 if (op.getFieldIndex() >=
5332 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5334 return op.emitOpError(
"subfield element index is greater than the number "
5335 "of fields in the bundle type");
5338LogicalResult SubfieldOp::verify() {
5339 return verifySubfieldLike<SubfieldOp>(*
this);
5341LogicalResult OpenSubfieldOp::verify() {
5342 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5345LogicalResult SubtagOp::verify() {
5346 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5347 return emitOpError(
"subfield element index is greater than the number "
5348 "of fields in the bundle type");
5358 SmallVector<Operation *, 8> worklist({op});
5362 bool constant =
true;
5368 while (constant && !(worklist.empty()))
5369 TypeSwitch<Operation *>(worklist.pop_back_val())
5370 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5371 if (
auto definingOp = op.getInput().getDefiningOp())
5372 worklist.push_back(definingOp);
5375 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5376 for (
auto &use : op.getResult().getUses())
5377 worklist.push_back(use.getOwner());
5379 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5380 .Default([&](
auto) { constant =
false; });
5389 if (
auto *op = value.getDefiningOp())
5394LogicalResult ConstCastOp::verify() {
5396 return emitOpError() << getInput().getType()
5397 <<
" is not 'const'-castable to "
5398 << getResult().getType();
5402FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5403 std::optional<Location> loc) {
5404 auto inType = type_cast<BundleType>(type);
5406 if (fieldIndex >= inType.getNumElements())
5408 "subfield element index is greater than the "
5409 "number of fields in the bundle type");
5413 return inType.getElementTypePreservingConst(fieldIndex);
5416FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5417 std::optional<Location> loc) {
5418 auto inType = type_cast<OpenBundleType>(type);
5420 if (fieldIndex >= inType.getNumElements())
5422 "subfield element index is greater than the "
5423 "number of fields in the bundle type");
5427 return inType.getElementTypePreservingConst(fieldIndex);
5430bool SubfieldOp::isFieldFlipped() {
5431 BundleType bundle = getInput().getType();
5432 return bundle.getElement(getFieldIndex()).isFlip;
5434bool OpenSubfieldOp::isFieldFlipped() {
5435 auto bundle = getInput().getType();
5436 return bundle.getElement(getFieldIndex()).isFlip;
5439FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5440 std::optional<Location> loc) {
5441 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5442 if (fieldIndex < vectorType.getNumElements())
5443 return vectorType.getElementTypePreservingConst();
5445 "' in vector type ", type);
5450FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5451 std::optional<Location> loc) {
5452 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5453 if (fieldIndex < vectorType.getNumElements())
5454 return vectorType.getElementTypePreservingConst();
5456 "' in vector type ", type);
5462FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5463 PropertyRef properties,
5464 mlir::RegionRange regions,
5465 std::optional<Location> loc) {
5466 Adaptor adaptor(operands, attrs, properties, regions);
5467 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5468 auto fieldIndex = adaptor.getFieldIndex();
5470 if (fieldIndex >= inType.getNumElements())
5472 "subtag element index is greater than the "
5473 "number of fields in the enum type");
5477 auto elementType = inType.getElement(fieldIndex).type;
5481FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5482 std::optional<Location> loc) {
5483 if (!type_isa<UIntType>(indexType))
5487 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5489 return vectorType.getElementTypePreservingConst();
5490 return vectorType.getElementType().getAllConstDroppedType();
5498 std::optional<Location> loc) {
5499 auto inType = type_cast<FEnumType>(input);
5500 return UIntType::get(inType.getContext(), inType.getTagWidth());
5503ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5504 OpAsmParser::UnresolvedOperand index;
5505 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5506 Type indexType, elemType;
5508 if (parser.parseOperand(index) || parser.parseComma() ||
5509 parser.parseOperandList(inputs) ||
5510 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5511 parser.parseType(indexType) || parser.parseComma() ||
5512 parser.parseType(elemType))
5515 if (parser.resolveOperand(index, indexType, result.operands))
5518 result.addTypes(elemType);
5520 return parser.resolveOperands(inputs, elemType, result.operands);
5523void MultibitMuxOp::print(OpAsmPrinter &p) {
5524 p <<
" " << getIndex() <<
", ";
5525 p.printOperands(getInputs());
5526 p.printOptionalAttrDict((*this)->getAttrs());
5527 p <<
" : " << getIndex().getType() <<
", " << getType();
5530FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5531 DictionaryAttr attrs,
5532 PropertyRef properties,
5533 mlir::RegionRange regions,
5534 std::optional<Location> loc) {
5535 if (operands.size() < 2)
5539 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5540 return operands[1].getType() == op.getType();
5544 return type_cast<FIRRTLType>(operands[1].getType());
5551LogicalResult ObjectSubfieldOp::inferReturnTypes(
5552 MLIRContext *
context, std::optional<mlir::Location> location,
5553 ValueRange operands, DictionaryAttr attributes, PropertyRef properties,
5554 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5556 inferReturnType(operands, attributes, properties, regions, location);
5559 inferredReturnTypes.push_back(type);
5563Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5564 std::optional<Location> loc) {
5565 auto classType = dyn_cast<ClassType>(inType);
5569 if (classType.getNumElements() <= fieldIndex)
5571 "number of fields in the object");
5572 return classType.getElement(fieldIndex).type;
5575void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5576 auto input = getInput();
5577 auto classType = input.getType();
5578 p <<
' ' << input <<
"[";
5579 p.printKeywordOrString(classType.getElement(getIndex()).name);
5581 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5582 p <<
" : " << classType;
5585ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5586 OperationState &result) {
5587 auto *
context = parser.getContext();
5589 OpAsmParser::UnresolvedOperand input;
5590 std::string fieldName;
5591 ClassType inputType;
5592 if (parser.parseOperand(input) || parser.parseLSquare() ||
5593 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5594 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5595 parser.parseType(inputType) ||
5596 parser.resolveOperand(input, inputType, result.operands))
5599 auto index = inputType.getElementIndex(fieldName);
5601 return parser.emitError(parser.getNameLoc(),
5602 "unknown field " + fieldName +
" in class type ")
5604 result.getOrAddProperties<Properties>().setIndex(
5605 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5607 SmallVector<Type> inferredReturnTypes;
5608 if (failed(inferReturnTypes(
context, result.location, result.operands,
5609 result.attributes.getDictionary(
context),
5610 result.getRawProperties(), result.regions,
5611 inferredReturnTypes)))
5613 result.addTypes(inferredReturnTypes);
5630 int32_t &rhsWidth,
bool &isConstResult,
5631 std::optional<Location> loc) {
5633 auto lhsi = type_dyn_cast<IntType>(lhs);
5634 auto rhsi = type_dyn_cast<IntType>(rhs);
5635 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5638 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5640 else if (!lhsi && rhsi)
5641 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5643 else if (!lhsi && !rhsi)
5644 mlir::emitError(*loc,
"operands must be integer types, not ")
5645 << lhs <<
" and " << rhs;
5647 mlir::emitError(*loc,
"operand signedness must match");
5652 lhsWidth = lhsi.getWidthOrSentinel();
5653 rhsWidth = rhsi.getWidthOrSentinel();
5654 isConstResult = lhsi.isConst() && rhsi.isConst();
5659 assert(op->getNumOperands() == 2 &&
5660 "SameOperandsIntTypeKind on non-binary op");
5661 int32_t lhsWidth, rhsWidth;
5664 op->getOperand(1).getType(), lhsWidth,
5665 rhsWidth, isConstResult, op->getLoc()));
5669 std::optional<Location> loc) {
5670 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5671 bool isConstResult =
false;
5675 if (lhsWidth != -1 && rhsWidth != -1)
5676 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5677 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5682 std::optional<Location> loc) {
5683 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5684 bool isConstResult =
false;
5688 if (lhsWidth != -1 && rhsWidth != -1)
5689 resultWidth = lhsWidth + rhsWidth;
5691 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5696 std::optional<Location> loc) {
5697 int32_t lhsWidth, rhsWidth;
5698 bool isConstResult =
false;
5703 if (type_isa<UIntType>(lhs))
5704 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5707 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5708 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5712 std::optional<Location> loc) {
5713 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5714 bool isConstResult =
false;
5718 if (lhsWidth != -1 && rhsWidth != -1)
5719 resultWidth = std::min(lhsWidth, rhsWidth);
5720 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5725 std::optional<Location> loc) {
5726 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5727 bool isConstResult =
false;
5731 if (lhsWidth != -1 && rhsWidth != -1) {
5732 resultWidth = std::max(lhsWidth, rhsWidth);
5733 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5736 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5740 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5744 std::optional<Location> loc) {
5745 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5748 auto lhsVec = type_cast<FVectorType>(lhs);
5749 auto rhsVec = type_cast<FVectorType>(rhs);
5751 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5756 rhsVec.getElementTypePreservingConst(), loc);
5759 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5760 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5761 lhsVec.isConst() && rhsVec.isConst() &&
5762 elemBaseType.isConst());
5766 std::optional<Location> loc) {
5767 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5770FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5771 PropertyRef properties,
5772 mlir::RegionRange regions,
5773 std::optional<Location> loc) {
5775 if (operands.empty())
5776 return UIntType::get(attrs.getContext(), 0);
5779 bool isSigned = type_isa<SIntType>(operands[0].getType());
5780 for (
auto operand : operands) {
5781 auto type = type_dyn_cast<IntType>(operand.getType());
5784 if (type.isSigned() != isSigned)
5786 "all operands must have same signedness");
5790 int32_t resultWidth = 0;
5791 bool isConstResult =
true;
5793 for (
auto operand : operands) {
5794 auto type = type_cast<IntType>(operand.getType());
5795 int32_t width = type.getWidthOrSentinel();
5802 if (resultWidth != -1)
5803 resultWidth += width;
5806 isConstResult &= type.isConst();
5810 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5814 std::optional<Location> loc) {
5815 auto lhsi = type_dyn_cast<IntType>(lhs);
5816 auto rhsui = type_dyn_cast<UIntType>(rhs);
5817 if (!rhsui || !lhsi)
5819 loc,
"first operand should be integer, second unsigned int");
5823 auto width = lhsi.getWidthOrSentinel();
5824 if (width == -1 || !rhsui.getWidth().has_value()) {
5827 auto amount = *rhsui.getWidth();
5830 "shift amount too large: second operand of "
5831 "dshl is wider than 31 bits");
5832 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5833 if (newWidth > INT32_MAX)
5835 loc,
"shift amount too large: first operand shifted by maximum "
5836 "amount exceeds maximum width");
5839 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5840 lhsi.
isConst() && rhsui.isConst());
5844 std::optional<Location> loc) {
5845 auto lhsi = type_dyn_cast<IntType>(lhs);
5846 auto rhsu = type_dyn_cast<UIntType>(rhs);
5849 loc,
"first operand should be integer, second unsigned int");
5850 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5854 std::optional<Location> loc) {
5855 auto lhsi = type_dyn_cast<IntType>(lhs);
5856 auto rhsu = type_dyn_cast<UIntType>(rhs);
5859 loc,
"first operand should be integer, second unsigned int");
5860 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5868 std::optional<Location> loc) {
5869 return UIntType::get(input.getContext(), 32);
5873 std::optional<Location> loc) {
5874 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5877 int32_t width = base.getBitWidthOrSentinel();
5880 return SIntType::get(input.getContext(), width, base.
isConst());
5884 std::optional<Location> loc) {
5885 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5888 int32_t width = base.getBitWidthOrSentinel();
5891 return UIntType::get(input.getContext(), width, base.
isConst());
5895 std::optional<Location> loc) {
5896 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5899 "operand must be single bit scalar base type");
5900 int32_t width = base.getBitWidthOrSentinel();
5901 if (width == -2 || width == 0 || width > 1)
5903 return AsyncResetType::get(input.getContext(), base.
isConst());
5907 std::optional<Location> loc) {
5908 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5911 return ResetType::get(input.getContext(), base.
isConst());
5915 std::optional<Location> loc) {
5916 return ClockType::get(input.getContext(),
isConst(input));
5920 std::optional<Location> loc) {
5921 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5922 auto width = uiType.getWidthOrSentinel();
5925 return SIntType::get(input.getContext(), width, uiType.
isConst());
5928 if (type_isa<SIntType>(input))
5935 std::optional<Location> loc) {
5936 auto inputi = type_dyn_cast<IntType>(input);
5939 int32_t width = inputi.getWidthOrSentinel();
5942 return SIntType::get(input.getContext(), width, inputi.
isConst());
5946 std::optional<Location> loc) {
5947 auto inputi = type_dyn_cast<IntType>(input);
5950 if (isa<UIntType>(inputi))
5952 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5957 std::optional<Location> loc) {
5958 return UIntType::get(input.getContext(), 1,
isConst(input));
5967 std::optional<Location> loc) {
5968 auto inputi = type_dyn_cast<IntType>(input);
5971 loc,
"input type should be the int type but got ", input);
5976 loc,
"high must be equal or greater than low, but got high = ", high,
5984 int32_t width = inputi.getWidthOrSentinel();
5985 if (width != -1 && high >= width)
5988 "high must be smaller than the width of input, but got high = ", high,
5989 ", width = ", width);
5991 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5995 std::optional<Location> loc) {
5997 auto inputi = type_dyn_cast<IntType>(input);
5998 if (amount < 0 || !inputi)
6000 loc,
"operand must have integer type and amount must be >= 0");
6002 int32_t width = inputi.getWidthOrSentinel();
6003 if (width != -1 && amount > width)
6006 return UIntType::get(input.getContext(), amount, inputi.
isConst());
6021 bool isConstCondition,
6022 std::optional<Location> loc) {
6028 if (high.getTypeID() != low.getTypeID())
6029 return emitInferRetTypeError<FIRRTLBaseType>(
6030 loc,
"incompatible mux operand types, true value type: ", high,
6031 ", false value type: ", low);
6033 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
6038 if (type_isa<IntType>(low)) {
6043 if (highWidth == -1)
6045 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
6050 auto highEnum = type_dyn_cast<FEnumType>(high);
6051 auto lowEnum = type_dyn_cast<FEnumType>(low);
6052 if (lowEnum && highEnum) {
6053 if (lowEnum.getNumElements() != highEnum.getNumElements())
6054 return emitInferRetTypeError<FIRRTLBaseType>(
6055 loc,
"incompatible mux operand types, true value type: ", high,
6056 ", false value type: ", low);
6057 SmallVector<FEnumType::EnumElement> elements;
6058 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6060 if (high.name != low.name || high.value != low.value)
6061 return emitInferRetTypeError<FIRRTLBaseType>(
6062 loc,
"incompatible mux operand types, true value type: ", highEnum,
6063 ", false value type: ", lowEnum);
6070 elements.emplace_back(high.name, high.value, inner);
6072 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6076 auto highVector = type_dyn_cast<FVectorType>(high);
6077 auto lowVector = type_dyn_cast<FVectorType>(low);
6078 if (highVector && lowVector &&
6079 highVector.getNumElements() == lowVector.getNumElements()) {
6081 lowVector.getElementTypePreservingConst(),
6082 isConstCondition, loc);
6085 return FVectorType::get(inner, lowVector.getNumElements(),
6090 auto highBundle = type_dyn_cast<BundleType>(high);
6091 auto lowBundle = type_dyn_cast<BundleType>(low);
6092 if (highBundle && lowBundle) {
6093 auto highElements = highBundle.getElements();
6094 auto lowElements = lowBundle.getElements();
6097 SmallVector<BundleType::BundleElement> newElements;
6099 bool failed =
false;
6101 if (highElements[i].name != lowElements[i].name ||
6102 highElements[i].isFlip != lowElements[i].isFlip) {
6106 auto element = highElements[i];
6108 highBundle.getElementTypePreservingConst(i),
6109 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6112 newElements.push_back(element);
6115 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6117 return emitInferRetTypeError<FIRRTLBaseType>(
6118 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6119 ", false value type: ", low);
6124 return emitInferRetTypeError<FIRRTLBaseType>(
6125 loc,
"invalid mux operand types, true value type: ", high,
6126 ", false value type: ", low);
6131 std::optional<Location> loc) {
6132 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6133 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6134 if (!highType || !lowType)
6139FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6140 DictionaryAttr attrs,
6141 PropertyRef properties,
6142 mlir::RegionRange regions,
6143 std::optional<Location> loc) {
6144 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6145 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6146 if (!highType || !lowType)
6152FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6153 DictionaryAttr attrs,
6154 PropertyRef properties,
6155 mlir::RegionRange regions,
6156 std::optional<Location> loc) {
6157 SmallVector<FIRRTLBaseType> types;
6159 for (
unsigned i = 1; i < 5; i++) {
6160 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6165 isConst(operands[0].getType()), loc);
6169 result = types.back();
6176 std::optional<Location> loc) {
6177 auto inputi = type_dyn_cast<IntType>(input);
6178 if (amount < 0 || !inputi)
6180 loc,
"pad input must be integer and amount must be >= 0");
6182 int32_t width = inputi.getWidthOrSentinel();
6186 width = std::max<int32_t>(width, amount);
6187 return IntType::get(input.getContext(), inputi.isSigned(), width,
6192 std::optional<Location> loc) {
6193 auto inputi = type_dyn_cast<IntType>(input);
6194 if (amount < 0 || !inputi)
6196 loc,
"shl input must be integer and amount must be >= 0");
6198 int32_t width = inputi.getWidthOrSentinel();
6202 return IntType::get(input.getContext(), inputi.isSigned(), width,
6207 std::optional<Location> loc) {
6208 auto inputi = type_dyn_cast<IntType>(input);
6209 if (amount < 0 || !inputi)
6211 loc,
"shr input must be integer and amount must be >= 0");
6213 int32_t width = inputi.getWidthOrSentinel();
6216 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6217 width = std::max<int32_t>(minWidth, width - amount);
6220 return IntType::get(input.getContext(), inputi.isSigned(), width,
6225 std::optional<Location> loc) {
6227 auto inputi = type_dyn_cast<IntType>(input);
6228 if (amount < 0 || !inputi)
6230 loc,
"tail input must be integer and amount must be >= 0");
6232 int32_t width = inputi.getWidthOrSentinel();
6236 loc,
"amount must be less than or equal operand width");
6247void VerbatimExprOp::getAsmResultNames(
6248 function_ref<
void(Value, StringRef)> setNameFn) {
6252 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6253 auto name = getText();
6255 if (name.starts_with(
"`"))
6256 name = name.drop_front();
6257 name = name.take_while(isOkCharacter);
6259 setNameFn(getResult(), name);
6266void VerbatimWireOp::getAsmResultNames(
6267 function_ref<
void(Value, StringRef)> setNameFn) {
6271 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6272 auto name = getText();
6274 if (name.starts_with(
"`"))
6275 name = name.drop_front();
6276 name = name.take_while(isOkCharacter);
6278 setNameFn(getResult(), name);
6289 op->emitError() <<
"unknown width is not allowed for DPI";
6290 return WalkResult::interrupt();
6292 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6294 return WalkResult::advance();
6296 <<
"integer types used by DPI functions must have a "
6297 "specific bit width; "
6298 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6299 "32(int), 64(longint) "
6300 "or greater than 64, but got "
6302 return WalkResult::interrupt();
6307LogicalResult DPICallIntrinsicOp::verify() {
6308 if (
auto inputNames = getInputNames()) {
6309 if (getInputs().size() != inputNames->size())
6310 return emitError() <<
"inputNames has " << inputNames->size()
6311 <<
" elements but there are " << getInputs().size()
6312 <<
" input arguments";
6314 if (
auto outputName = getOutputName())
6315 if (getNumResults() == 0)
6316 return emitError() <<
"output name is given but there is no result";
6318 auto checkType = [
this](Type type) {
6321 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6322 llvm::all_of(this->getOperandTypes(), checkType));
6325SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6326DPICallIntrinsicOp::computeDataFlow() {
6330 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6332 for (
auto operand : getOperands()) {
6333 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6335 SmallVector<circt::FieldRef> operandFields;
6338 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6342 for (
auto result : getResults())
6345 for (
auto field : operandFields)
6346 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6356LogicalResult HWStructCastOp::verify() {
6358 BundleType bundleType;
6359 hw::StructType structType;
6360 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6361 structType = dyn_cast<hw::StructType>(getType());
6363 return emitError(
"result type must be a struct");
6364 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6365 structType = dyn_cast<hw::StructType>(getOperand().getType());
6367 return emitError(
"operand type must be a struct");
6369 return emitError(
"either source or result type must be a bundle type");
6372 auto firFields = bundleType.getElements();
6373 auto hwFields = structType.getElements();
6374 if (firFields.size() != hwFields.size())
6375 return emitError(
"bundle and struct have different number of fields");
6377 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6378 if (firFields[findex].name.getValue() != hwFields[findex].name)
6379 return emitError(
"field names don't match '")
6380 << firFields[findex].name.getValue() <<
"', '"
6381 << hwFields[findex].name.getValue() <<
"'";
6385 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6386 return emitError(
"size of field '")
6387 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6394LogicalResult BitCastOp::verify() {
6395 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6397 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6399 if (*inTypeBits == *resTypeBits) {
6402 return emitError(
"cannot cast non-'const' input type ")
6403 << getOperand().getType() <<
" to 'const' result type "
6407 return emitError(
"the bitwidth of input (")
6408 << *inTypeBits <<
") and result (" << *resTypeBits
6411 if (!inTypeBits.has_value())
6412 return emitError(
"bitwidth cannot be determined for input operand type ")
6413 << getInput().getType();
6414 return emitError(
"bitwidth cannot be determined for result type ")
6425 NamedAttrList &resultAttrs) {
6426 auto result = parser.parseOptionalAttrDict(resultAttrs);
6427 if (!resultAttrs.get(
"annotations"))
6428 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6434 DictionaryAttr attr,
6435 ArrayRef<StringRef> extraElides = {}) {
6436 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6438 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6439 elidedAttrs.push_back(
"annotations");
6441 elidedAttrs.push_back(
"nameKind");
6443 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6449 NamedAttrList &resultAttrs) {
6452 if (!resultAttrs.get(
"portAnnotations")) {
6453 SmallVector<Attribute, 16> portAnnotations(
6454 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6455 resultAttrs.append(
"portAnnotations",
6456 parser.getBuilder().getArrayAttr(portAnnotations));
6463 DictionaryAttr attr,
6464 ArrayRef<StringRef> extraElides = {}) {
6465 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6467 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6468 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6469 elidedAttrs.push_back(
"portAnnotations");
6478 firrtl::NameKindEnumAttr &result) {
6481 if (!parser.parseOptionalKeyword(&keyword,
6482 {
"interesting_name",
"droppable_name"})) {
6483 auto kind = symbolizeNameKindEnum(keyword);
6484 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6490 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6495 firrtl::NameKindEnumAttr attr,
6496 ArrayRef<StringRef> extraElides = {}) {
6497 if (attr.getValue() != NameKindEnum::DroppableName)
6498 p <<
" " << stringifyNameKindEnum(attr.getValue());
6506 NamedAttrList &resultAttrs) {
6514 DictionaryAttr attrs) {
6515 SmallVector<StringRef, 4> elides;
6517 elides.push_back(Forceable::getForceableAttrName());
6527 OpAsmParser &parser,
6528 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &fieldValues,
6529 SmallVectorImpl<Type> &fieldTypes, Type &resultType) {
6531 if (parser.parseType(resultType))
6534 auto domainType = dyn_cast<DomainType>(resultType);
6536 return parser.emitError(parser.getCurrentLocation(),
6537 "expected domain type");
6540 auto fields = domainType.getFields();
6543 if (fieldValues.size() != fields.size())
6544 return parser.emitError(parser.getCurrentLocation(),
6545 "number of field values (" +
6546 Twine(fieldValues.size()) +
6547 ") does not match domain field count (" +
6548 Twine(fields.size()) +
")");
6551 fieldTypes.reserve(fields.size());
6552 for (
auto field : fields)
6553 fieldTypes.push_back(cast<DomainFieldAttr>(field).getType());
6559 OperandRange fieldValues,
6560 TypeRange fieldTypes, Type resultType) {
6568static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6573static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6584 if (ClassType::parseInterface(parser, type))
6591 type.printInterface(p);
6599 NamedAttrList &resultAttrs) {
6600 auto result = p.parseOptionalAttrDict(resultAttrs);
6601 if (!resultAttrs.get(
"name"))
6602 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6608 DictionaryAttr attr,
6609 ArrayRef<StringRef> extraElides = {}) {
6610 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6611 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6612 elides.push_back(
"name");
6614 p.printOptionalAttrDict(op->getAttrs(), elides);
6618 NamedAttrList &resultAttrs) {
6623 DictionaryAttr attr) {
6628 NamedAttrList &resultAttrs) {
6633 DictionaryAttr attr) {
6635 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6643 DictionaryAttr attr) {
6652 DictionaryAttr attr) {
6661 OpAsmSetValueNameFn setNameFn) {
6664 if (op->getNumResults() == 1)
6665 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6666 setNameFn(op->getResult(0), nameAttr.getValue());
6669void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6673void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6677void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6681void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6684void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6687void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6690void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6693void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6696void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6699void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6702void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6705void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6708void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6711void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6714void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6717void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6720void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6723void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6726void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6729void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6732void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6735void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6738void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6741void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6744void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6747void BoolAndOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6750void BoolOrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6753void BoolXorOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6756void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6759void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6762void PlusArgsValueIntrinsicOp::getAsmResultNames(
6763 OpAsmSetValueNameFn setNameFn) {
6766void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6769void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6772void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6775void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6778void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6781void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6784void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6787void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6790void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6793void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6796void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6799void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6802void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6805void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6808void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6811void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6814void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6818void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6822void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6826void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6830void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6834void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6838void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6842void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6846void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6850void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6854void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6858void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6862void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6866void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6870void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6874void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6878void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6886void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6890void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6894void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6898void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6902void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6906FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6907 DictionaryAttr attrs,
6908 PropertyRef properties,
6909 mlir::RegionRange regions,
6910 std::optional<Location> loc) {
6911 Type inType = operands[0].getType();
6912 auto inRefType = type_dyn_cast<RefType>(inType);
6915 loc,
"ref.resolve operand must be ref type, not ", inType);
6916 return inRefType.getType();
6919FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6920 PropertyRef properties,
6921 mlir::RegionRange regions,
6922 std::optional<Location> loc) {
6923 Type inType = operands[0].getType();
6924 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6927 loc,
"ref.send operand must be base type, not ", inType);
6928 return RefType::get(inBaseType.getPassiveType());
6931FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6932 std::optional<Location> loc) {
6933 auto refType = type_dyn_cast<RefType>(type);
6936 auto inType = refType.getType();
6942 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6943 if (fieldIndex < vectorType.getNumElements())
6944 return RefType::get(
6945 vectorType.getElementType().getConstType(
6946 vectorType.isConst() || vectorType.getElementType().isConst()),
6947 refType.getForceable(), refType.getLayer());
6949 "' in RefType of vector type ", refType);
6951 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6952 if (fieldIndex >= bundleType.getNumElements()) {
6954 "subfield element index is greater than "
6955 "the number of fields in the bundle type");
6957 return RefType::get(
6958 bundleType.getElement(fieldIndex)
6960 bundleType.isConst() ||
6961 bundleType.getElement(fieldIndex).type.isConst()),
6962 refType.getForceable(), refType.getLayer());
6966 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6969LogicalResult RefCastOp::verify() {
6973 getOperation(), srcLayers, dstLayers,
6974 "cannot discard layer requirements of input reference",
6975 "discarding layer requirements");
6978LogicalResult RefResolveOp::verify() {
6982 getOperation(), srcLayers, dstLayers,
6983 "ambient layers are insufficient to resolve reference");
6987 auto targetRef = getTarget();
6988 if (targetRef.getModule() !=
6989 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6990 return emitOpError() <<
"has non-local target";
6992 auto target = ns.
lookup(targetRef);
6994 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6996 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
7001 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
7002 if (!baseType || baseType.getPassiveType() != getType().getType()) {
7003 auto diag = emitOpError(
"has type mismatch: target resolves to ")
7004 << fType <<
" instead of expected " << getType().getType();
7005 diag.attachNote(loc) <<
"target resolves here";
7010 if (target.isPort()) {
7011 auto mod = cast<FModuleLike>(target.getOp());
7012 return checkFinalType(mod.getPortType(target.getPort()),
7013 mod.getPortLocation(target.getPort()));
7015 hw::InnerSymbolOpInterface symOp =
7016 cast<hw::InnerSymbolOpInterface>(target.getOp());
7017 if (!symOp.getTargetResult())
7018 return emitOpError(
"has target that cannot be probed")
7019 .attachNote(symOp.getLoc())
7020 .append(
"target resolves here");
7022 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
7023 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
7024 return emitOpError(
"is not dominated by target")
7025 .attachNote(symOp.getLoc())
7026 .append(
"target here");
7027 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
7030LogicalResult RefForceOp::verify() {
7034 getOperation(), destLayers, ambientLayers,
7035 "has insufficient ambient layers to force its reference");
7038LogicalResult RefForceInitialOp::verify() {
7042 getOperation(), destLayers, ambientLayers,
7043 "has insufficient ambient layers to force its reference");
7046LogicalResult RefReleaseOp::verify() {
7050 getOperation(), destLayers, ambientLayers,
7051 "has insufficient ambient layers to release its reference");
7054LogicalResult RefReleaseInitialOp::verify() {
7058 getOperation(), destLayers, ambientLayers,
7059 "has insufficient ambient layers to release its reference");
7062LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7063 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7065 return emitOpError(
"has an invalid symbol reference");
7067 if (!isa<hw::HierPathOp>(target))
7068 return emitOpError(
"does not target a hierpath op");
7074LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7075 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7077 return emitOpError(
"has an invalid symbol reference");
7079 if (!isa<hw::HierPathOp>(target))
7080 return emitOpError(
"does not target a hierpath op");
7090LogicalResult LayerBlockOp::verify() {
7091 auto layerName = getLayerName();
7092 auto *parentOp = (*this)->getParentOp();
7095 while (isa<WhenOp, MatchOp>(parentOp))
7096 parentOp = parentOp->getParentOp();
7100 auto nestedReferences = layerName.getNestedReferences();
7101 if (nestedReferences.empty()) {
7102 if (!isa<FModuleOp>(parentOp)) {
7103 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7104 "not have a 'firrtl.module' op as a parent";
7105 return diag.attachNote(parentOp->getLoc())
7106 <<
"illegal parent op defined here";
7109 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7110 if (!parentLayerBlock) {
7111 auto diag = emitOpError()
7112 <<
"has a nested layer symbol, but does not have a '"
7113 << getOperationName() <<
"' op as a parent'";
7114 return diag.attachNote(parentOp->getLoc())
7115 <<
"illegal parent op defined here";
7117 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7118 if (parentLayerBlockName.getRootReference() !=
7119 layerName.getRootReference() ||
7120 parentLayerBlockName.getNestedReferences() !=
7121 layerName.getNestedReferences().drop_back()) {
7122 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7123 return diag.attachNote(parentLayerBlock->getLoc())
7124 <<
"illegal parent layer block defined here";
7130 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7131 [&](Operation *op) -> WalkResult {
7133 if (isa<LayerBlockOp>(op))
7134 return WalkResult::skip();
7138 for (
auto operand : op->getOperands()) {
7140 if (
auto *definingOp = operand.getDefiningOp())
7144 auto type = operand.getType();
7147 if (isa<PropertyType>(type)) {
7148 auto diag = emitOpError() <<
"captures a property operand";
7149 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7150 diag.attachNote(op->getLoc()) <<
"operand is used here";
7151 return WalkResult::interrupt();
7156 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7158 if (isa<RefDefineOp>(connect))
7159 return WalkResult::advance();
7166 bool passive =
true;
7168 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7169 passive = type.isPassive();
7178 return WalkResult::advance();
7181 return WalkResult::advance();
7185 <<
"connects to a destination which is defined outside its "
7186 "enclosing layer block";
7187 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7188 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7189 return WalkResult::interrupt();
7192 return WalkResult::advance();
7195 return failure(result.wasInterrupted());
7199LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7201 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7203 return emitOpError(
"invalid symbol reference");
7213void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7214 setNameFn(getResult(),
"time");
7217void HierarchicalModuleNameOp::getAsmResultNames(
7218 OpAsmSetValueNameFn setNameFn) {
7219 setNameFn(getResult(),
"hierarchicalmodulename");
7222ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7223 ::mlir::OperationState &result) {
7225 OpAsmParser::UnresolvedOperand clock, cond;
7226 if (parser.parseOperand(clock) || parser.parseComma() ||
7227 parser.parseOperand(cond) || parser.parseComma())
7231 [&parser](llvm::SMLoc &loc, StringAttr &result,
7232 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7234 loc = parser.getCurrentLocation();
7237 std::string resultStr;
7238 if (parser.parseString(&resultStr))
7240 result = parser.getBuilder().getStringAttr(resultStr);
7243 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7249 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7251 llvm::SMLoc outputFileLoc, formatStringLoc;
7255 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7256 outputFileSubstitutions) ||
7257 parser.parseComma() ||
7260 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7268 Type clockType, condType;
7269 SmallVector<Type> restTypes;
7271 if (parser.parseColon() || parser.parseType(clockType) ||
7272 parser.parseComma() || parser.parseType(condType))
7275 if (succeeded(parser.parseOptionalComma())) {
7276 if (parser.parseTypeList(restTypes))
7281 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7282 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7283 static_cast<int32_t
>(substitutions.size())};
7286 if (parser.resolveOperand(clock, clockType, result.operands) ||
7287 parser.resolveOperand(cond, condType, result.operands) ||
7288 parser.resolveOperands(
7289 outputFileSubstitutions,
7290 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7291 outputFileLoc, result.operands) ||
7292 parser.resolveOperands(
7294 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7295 formatStringLoc, result.operands))
7301void FPrintFOp::print(OpAsmPrinter &p) {
7302 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7303 p.printAttributeWithoutType(getOutputFileAttr());
7304 if (!getOutputFileSubstitutions().
empty()) {
7306 p.printOperands(getOutputFileSubstitutions());
7310 p.printAttributeWithoutType(getFormatStringAttr());
7311 if (!getSubstitutions().
empty()) {
7313 p.printOperands(getSubstitutions());
7317 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7318 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7319 for (
auto type : getOperands().drop_front(2).getTypes()) {
7330LogicalResult FFlushOp::verify() {
7331 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7332 return emitOpError(
"substitutions without output file are not allowed");
7341 auto ref = getInstanceAttr();
7342 auto target = ns.
lookup(ref);
7344 return emitError() <<
"target " << ref <<
" cannot be resolved";
7346 if (!target.isOpOnly())
7347 return emitError() <<
"target " << ref <<
" is not an operation";
7349 auto instance = dyn_cast<InstanceOp>(target.getOp());
7351 return emitError() <<
"target " << ref <<
" is not an instance";
7353 if (!instance.getDoNotPrint())
7354 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7363void DomainCreateAnonOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7368DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7369 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7370 auto domainAttr = getDomainAttr();
7372 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7374 return emitOpError() <<
"references undefined symbol '" << domainAttr
7377 if (!isa<DomainOp>(symbol))
7378 return emitOpError() <<
"references symbol '" << domainAttr
7379 <<
"' which is not a domain";
7382 auto domainType = getResult().getType();
7383 return domainType.verifySymbolUses(getOperation(), symbolTable);
7386void DomainCreateOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7391DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7392 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7393 auto domainAttr = getDomainAttr();
7395 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7397 return emitOpError() <<
"references undefined symbol '" << domainAttr
7400 if (!isa<DomainOp>(symbol))
7401 return emitOpError() <<
"references symbol '" << domainAttr
7402 <<
"' which is not a domain";
7405 auto domainType = getResult().getType();
7406 return domainType.verifySymbolUses(getOperation(), symbolTable);
7409LogicalResult DomainCreateOp::verify() {
7411 auto domainType = getResult().getType();
7412 auto fields = domainType.getFields();
7413 auto fieldValues = getFieldValues();
7416 if (fieldValues.size() != fields.size())
7417 return emitOpError() <<
"has " << fieldValues.size()
7418 <<
" field value(s) but domain '"
7419 << domainType.getName() <<
"' expects "
7420 << fields.size() <<
" field(s)";
7423 for (
size_t i = 0; i < fields.size(); ++i) {
7424 auto fieldAttr = cast<DomainFieldAttr>(fields[i]);
7425 auto expectedType = fieldAttr.getType();
7426 auto actualType = fieldValues[i].getType();
7428 if (expectedType == actualType)
7431 return emitOpError() <<
"field value " << i <<
" has type " << actualType
7432 <<
" but domain field '" << fieldAttr.getName()
7433 <<
"' expects type " << expectedType;
7443StringAttr DomainSubfieldOp::getFieldName() {
7444 auto domainType = getInput().getType();
7445 auto fields = domainType.getFields();
7446 auto index = getFieldIndex();
7448 if (index >= fields.size())
7451 return cast<DomainFieldAttr>(fields[index]).getName();
7454Type DomainSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
7455 std::optional<Location> loc) {
7456 auto domainType = dyn_cast<DomainType>(inType);
7460 auto fields = domainType.getFields();
7461 if (fieldIndex >= fields.size())
7463 loc,
"field index ", fieldIndex,
7464 +
" is greater than the number of fields in the domain");
7466 return cast<DomainFieldAttr>(fields[fieldIndex]).getType();
7469Type DomainSubfieldOp::inferReturnType(ValueRange operands,
7470 mlir::DictionaryAttr attrs,
7471 mlir::PropertyRef properties,
7472 mlir::RegionRange regions,
7473 std::optional<Location> loc) {
7474 Adaptor adaptor(operands, attrs, properties, regions);
7475 return inferReturnType(adaptor.getInput().getType(), adaptor.getFieldIndex(),
7479DomainSubfieldOp DomainSubfieldOp::create(OpBuilder &builder, Type resultType,
7480 Value base,
unsigned fieldIndex) {
7481 OperationState state(builder.getUnknownLoc(),
7482 DomainSubfieldOp::getOperationName());
7483 state.addOperands(base);
7484 state.addAttribute(
"fieldIndex", builder.getI32IntegerAttr(fieldIndex));
7485 state.addTypes(resultType);
7486 return cast<DomainSubfieldOp>(builder.create(state));
7489LogicalResult DomainSubfieldOp::inferReturnTypes(
7490 MLIRContext *
context, std::optional<Location> location, ValueRange operands,
7491 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
7492 SmallVectorImpl<Type> &inferredReturnTypes) {
7493 Adaptor adaptor(operands, attributes, properties, regions);
7494 auto resultType = inferReturnType(adaptor.getInput().getType(),
7495 adaptor.getFieldIndex(), location);
7498 inferredReturnTypes.push_back(resultType);
7502void DomainSubfieldOp::print(OpAsmPrinter &p) {
7503 p <<
' ' << getInput() <<
"[";
7506 p.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
7507 p <<
" : " << getInput().getType();
7510ParseResult DomainSubfieldOp::parse(OpAsmParser &parser,
7511 OperationState &result) {
7512 auto *
context = parser.getContext();
7514 OpAsmParser::UnresolvedOperand input;
7515 std::string fieldName;
7516 DomainType inputType;
7518 if (parser.parseOperand(input) || parser.parseLSquare() ||
7519 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
7520 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
7521 parser.parseType(inputType) ||
7522 parser.resolveOperand(input, inputType, result.operands))
7526 auto fieldIndex = inputType.getFieldIndex(fieldName);
7528 return parser.emitError(parser.getNameLoc(),
7529 "unknown field '" + fieldName +
"' in domain type");
7532 result.addAttribute(
7534 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
7537 auto resultType = inferReturnType(inputType, *fieldIndex, std::nullopt);
7541 result.addTypes(resultType);
7550#define GET_OP_CLASSES
7551#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 void printClassLike(OpAsmPrinter &p, ClassLike op)
static LogicalResult verifySubfieldLike(OpTy op)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult checkSingleConnect(FConnectLike connect)
Returns success if the given connect is the sole driver of its dest operand.
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static LogicalResult checkLayerCompatibility(Operation *op, const LayerSet &src, const LayerSet &dst, const Twine &errorMsg, const Twine ¬eMsg=Twine("missing layer requirements"))
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, bool supportsDomains, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs, SmallVectorImpl< Attribute > &domains)
Parse a list of module ports.
static LogicalResult checkConnectConditionality(FConnectLike connect)
Checks that connections to 'const' destinations are not dependent on non-'const' conditions in when b...
static void erasePorts(FModuleLike op, const llvm::BitVector &portIndices)
Erases the ports that have their corresponding bit set in portIndices.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static ParseResult parseFieldsFromDomain(OpAsmParser &parser, SmallVectorImpl< OpAsmParser::UnresolvedOperand > &fieldValues, SmallVectorImpl< Type > &fieldTypes, Type &resultType)
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printFieldsFromDomain(OpAsmPrinter &p, Operation *op, OperandRange fieldValues, TypeRange fieldTypes, Type resultType)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static void replaceUsesRespectingInsertedPorts(Operation *op1, Operation *op2, ArrayRef< std::pair< unsigned, PortInfo > > insertions)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static LogicalResult verifyInitialAttr(Operation *op, FIRRTLBaseType regType, IntegerAttr initial)
Verify that an optional initial time-zero value attribute is a constant of the correct ground type.
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 InstanceOp cloneWithErasedPorts(InstanceOp &instance, const llvm::BitVector &inErasures, const llvm::BitVector &outErasures)
Clone instance, but with ports deleted according to the inErasures and outErasures BitVectors.
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.
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 hasHardwareElements(FIRRTLType type)
Return true if the given type contains any elements of hardware types.
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...
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...
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.