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);
1484 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1485 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1486 p << visibility.getValue() <<
' ';
1489 p.printSymbolName(op.getModuleName());
1496 Block *body =
nullptr;
1497 if (!op->getRegion(0).empty())
1498 body = &op->getRegion(0).front();
1501 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1502 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1503 op.getDomainInfo());
1505 SmallVector<StringRef, 13> omittedAttrs = {
1506 "sym_name",
"portDirections",
"portTypes",
1507 "portAnnotations",
"portSymbols",
"portLocations",
1508 "parameters", visibilityAttrName,
"domainInfo"};
1510 if (op.getConvention() == Convention::Internal)
1511 omittedAttrs.push_back(
"convention");
1515 if (!needPortNamesAttr)
1516 omittedAttrs.push_back(
"portNames");
1519 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1520 omittedAttrs.push_back(
"annotations");
1523 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1524 if (knownLayers.empty())
1525 omittedAttrs.push_back(
"knownLayers");
1528 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1530 omittedAttrs.push_back(
"layers");
1533 if (
auto extReqs = op->getAttrOfType<ArrayAttr>(
"externalRequirements"))
1534 if (extReqs.empty())
1535 omittedAttrs.push_back(
"externalRequirements");
1537 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1546void FModuleOp::print(OpAsmPrinter &p) {
1552 Region &fbody = getBody();
1553 if (!fbody.empty()) {
1555 p.printRegion(fbody,
false,
1567 SmallVectorImpl<Attribute> ¶meters) {
1569 return parser.parseCommaSeparatedList(
1570 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1575 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1579 if (succeeded(parser.parseOptionalEqual())) {
1580 if (parser.parseAttribute(value, type))
1584 auto &builder = parser.getBuilder();
1585 parameters.push_back(ParamDeclAttr::get(
1586 builder.getContext(), builder.getStringAttr(name), type, value));
1593 ArrayAttr ¶meters) {
1594 SmallVector<Attribute> parseParameters;
1598 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1603template <
typename Properties,
typename =
void>
1606template <
typename Properties>
1608 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1609 : std::true_type {};
1611template <
typename OpTy>
1613 OperationState &result,
1614 bool hasSSAIdentifiers) {
1615 auto *
context = result.getContext();
1616 auto &builder = parser.getBuilder();
1617 using Properties =
typename OpTy::Properties;
1618 auto &properties = result.getOrAddProperties<Properties>();
1622 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1625 StringAttr nameAttr;
1626 if (parser.parseSymbolName(nameAttr))
1628 properties.setSymName(nameAttr);
1632 SmallVector<Attribute, 4> parameters;
1635 properties.setParameters(builder.getArrayAttr(parameters));
1639 SmallVector<OpAsmParser::Argument> entryArgs;
1640 SmallVector<Direction, 4> portDirections;
1641 SmallVector<Attribute, 4> portNames;
1642 SmallVector<Attribute, 4> portTypes;
1643 SmallVector<Attribute, 4> portAnnotations;
1644 SmallVector<Attribute, 4> portSyms;
1645 SmallVector<Attribute, 4> portLocs;
1646 SmallVector<Attribute, 4> domains;
1648 true, entryArgs, portDirections,
1649 portNames, portTypes, portAnnotations, portSyms,
1654 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1657 assert(portNames.size() == portTypes.size());
1663 properties.setPortDirections(
1667 properties.setPortNames(builder.getArrayAttr(portNames));
1670 properties.setPortTypes(ArrayAttr::get(
context, portTypes));
1674 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1675 return !cast<ArrayAttr>(anno).empty();
1677 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
1679 properties.setPortAnnotations(builder.getArrayAttr({}));
1682 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1683 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1686 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
1689 properties.setAnnotations(builder.getArrayAttr({}));
1692 if (llvm::all_of(domains, [&](Attribute attr) {
1693 auto arrayAttr = dyn_cast<ArrayAttr>(attr);
1694 return arrayAttr && arrayAttr.empty();
1696 properties.setDomainInfo(ArrayAttr::get(
context, {}));
1698 properties.setDomainInfo(ArrayAttr::get(
context, domains));
1701 auto *body = result.addRegion();
1703 if (hasSSAIdentifiers) {
1704 if (parser.parseRegion(*body, entryArgs))
1707 body->push_back(
new Block());
1712ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1713 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1716 auto &properties = result.getOrAddProperties<Properties>();
1717 properties.setConvention(
1718 ConventionAttr::get(result.getContext(), Convention::Internal));
1719 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1723ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1724 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1727 auto &properties = result.getOrAddProperties<Properties>();
1728 properties.setConvention(
1729 ConventionAttr::get(result.getContext(), Convention::Internal));
1730 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1734ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1735 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1739ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1740 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1744LogicalResult FModuleOp::verify() {
1747 auto portTypes = getPortTypes();
1748 auto portLocs = getPortLocations();
1749 auto numPorts = portTypes.size();
1752 if (body->getNumArguments() != numPorts)
1753 return emitOpError(
"entry block must have ")
1754 << numPorts <<
" arguments to match module signature";
1757 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1758 if (arg.getType() != cast<TypeAttr>(type).getValue())
1759 return emitOpError(
"block argument types should match signature types");
1760 if (arg.getLoc() != cast<LocationAttr>(loc))
1762 "block argument locations should match signature locations");
1768LogicalResult FExtModuleOp::verify() {
1769 auto params = getParameters();
1771 auto checkParmValue = [&](Attribute elt) ->
bool {
1772 auto param = cast<ParamDeclAttr>(elt);
1773 auto value = param.getValue();
1774 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1776 emitError() <<
"has unknown extmodule parameter value '"
1777 << param.getName().getValue() <<
"' = " << value;
1781 if (!llvm::all_of(params, checkParmValue))
1786 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1789 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1790 for (
auto attr : getPortTypes()) {
1791 auto type = cast<TypeAttr>(attr).getValue();
1792 if (
auto refType = type_dyn_cast<RefType>(type))
1793 if (
auto layer = refType.getLayer())
1794 referenced.insert(layer);
1798 "references unknown layers",
"unknown layers");
1801LogicalResult FIntModuleOp::verify() {
1802 auto params = getParameters();
1806 auto checkParmValue = [&](Attribute elt) ->
bool {
1807 auto param = cast<ParamDeclAttr>(elt);
1808 auto value = param.getValue();
1809 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1811 emitError() <<
"has unknown intmodule parameter value '"
1812 << param.getName().getValue() <<
"' = " << value;
1816 if (!llvm::all_of(params, checkParmValue))
1823 CircuitOp circuitOp,
1824 SymbolTableCollection &symbolTable,
1826 auto layer = refType.getLayer();
1829 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1831 return emitError(loc) << start <<
" associated with layer '" << layer
1832 <<
"', but this layer was not defined";
1833 if (!isa<LayerOp>(layerOp)) {
1834 auto diag = emitError(loc)
1835 << start <<
" associated with layer '" << layer
1836 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1837 << LayerOp::getOperationName() <<
"' op";
1838 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1844 SymbolTableCollection &symbolTable) {
1846 auto circuitOp =
module->getParentOfType<CircuitOp>();
1847 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1848 auto type =
module.getPortType(i);
1850 if (
auto refType = type_dyn_cast<RefType>(type)) {
1852 refType, module.getPortLocation(i), circuitOp, symbolTable,
1853 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1858 if (
auto classType = dyn_cast<ClassType>(type)) {
1859 auto className = classType.getNameAttr();
1860 auto classOp = dyn_cast_or_null<ClassLike>(
1861 symbolTable.lookupSymbolIn(circuitOp, className));
1863 return module.emitOpError() << "references unknown class " << className;
1866 if (failed(classOp.verifyType(classType,
1867 [&]() { return module.emitOpError(); })))
1872 if (
auto domainType = dyn_cast<DomainType>(type)) {
1874 domainType.verifySymbolUses(module.getOperation(), symbolTable)))
1883LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1887 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1888 for (
auto layer : getLayers()) {
1889 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1890 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1897FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1901 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
1902 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
1903 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1904 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
1906 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
1907 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
1908 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
1915FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1920FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1924void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1929void FExtModuleOp::getAsmBlockArgumentNames(
1934StringAttr FExtModuleOp::getExtModuleNameAttr() {
1935 if (
auto defnameAttr = getDefnameAttr(); defnameAttr && !defnameAttr.empty())
1937 return getNameAttr();
1940StringRef FExtModuleOp::getExtModuleName() {
1941 if (
auto defname = getDefname(); defname && !defname->empty())
1946void FIntModuleOp::getAsmBlockArgumentNames(
1951void FMemModuleOp::getAsmBlockArgumentNames(
1956ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1958ArrayAttr FModuleOp::getParameters() {
return {}; }
1960Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1962ConventionAttr FIntModuleOp::getConventionAttr() {
1963 return ConventionAttr::get(getContext(), getConvention());
1966Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1968ConventionAttr FMemModuleOp::getConventionAttr() {
1969 return ConventionAttr::get(getContext(), getConvention());
1977 ClassLike classOp, ClassType type,
1978 function_ref<InFlightDiagnostic()> emitError) {
1980 auto name = type.getNameAttr().getAttr();
1981 auto expectedName = classOp.getModuleNameAttr();
1982 if (name != expectedName)
1983 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1986 auto elements = type.getElements();
1988 auto expectedNumElements = classOp.getNumPorts();
1990 return emitError() <<
"has wrong number of ports, got " <<
numElements
1991 <<
", expected " << expectedNumElements;
1993 auto portNames = classOp.getPortNames();
1994 auto portDirections = classOp.getPortDirections();
1995 auto portTypes = classOp.getPortTypes();
1998 auto element = elements[i];
2000 auto name = element.name;
2001 auto expectedName = portNames[i];
2002 if (name != expectedName)
2003 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2004 <<
", expected " << expectedName;
2006 auto direction = element.direction;
2007 auto expectedDirection =
Direction(portDirections[i]);
2008 if (direction != expectedDirection)
2009 return emitError() <<
"port " << name <<
" has wrong direction, got "
2013 auto type = element.type;
2014 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2015 if (type != expectedType)
2016 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2017 <<
", expected " << expectedType;
2024 auto n = classOp.getNumPorts();
2025 SmallVector<ClassElement> elements;
2026 elements.reserve(n);
2027 for (
size_t i = 0; i < n; ++i)
2028 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2029 classOp.getPortDirection(i)});
2030 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2031 return ClassType::get(name, elements);
2034template <
typename OpTy>
2036 bool hasSSAIdentifiers) {
2037 auto *
context = result.getContext();
2038 auto &builder = parser.getBuilder();
2039 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2043 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2046 StringAttr nameAttr;
2047 if (parser.parseSymbolName(nameAttr))
2049 properties.setSymName(nameAttr);
2052 SmallVector<OpAsmParser::Argument> entryArgs;
2053 SmallVector<Direction, 4> portDirections;
2054 SmallVector<Attribute, 4> portNames;
2055 SmallVector<Attribute, 4> portTypes;
2056 SmallVector<Attribute, 4> portAnnotations;
2057 SmallVector<Attribute, 4> portSyms;
2058 SmallVector<Attribute, 4> portLocs;
2059 SmallVector<Attribute, 4> domains;
2062 entryArgs, portDirections, portNames, portTypes,
2063 portAnnotations, portSyms, portLocs, domains))
2067 for (
auto annos : portAnnotations)
2068 if (!cast<ArrayAttr>(annos).empty())
2072 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2075 assert(portNames.size() == portTypes.size());
2081 properties.setPortDirections(
2085 properties.setPortNames(builder.getArrayAttr(portNames));
2088 properties.setPortTypes(builder.getArrayAttr(portTypes));
2091 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2092 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2095 properties.setPortLocations(ArrayAttr::get(
context, portLocs));
2101 auto *bodyRegion = result.addRegion();
2103 if (hasSSAIdentifiers) {
2104 if (parser.parseRegion(*bodyRegion, entryArgs))
2106 if (bodyRegion->empty())
2107 bodyRegion->push_back(
new Block());
2117 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2118 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2119 p << visibility.getValue() <<
' ';
2122 p.printSymbolName(op.getName());
2126 Region ®ion = op->getRegion(0);
2127 Block *body =
nullptr;
2128 if (!region.empty())
2129 body = ®ion.front();
2132 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2133 {}, op.getPortSymbols(), op.getPortLocations(), {});
2136 SmallVector<StringRef, 8> omittedAttrs = {
2137 "sym_name",
"portNames",
"portTypes",
"portDirections",
2138 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2142 if (!needPortNamesAttr)
2143 omittedAttrs.push_back(
"portNames");
2145 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2148 if (!region.empty()) {
2150 auto printEntryBlockArgs =
false;
2151 auto printBlockTerminators =
false;
2152 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2160void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2161 ArrayRef<PortInfo> ports) {
2164 [](
const auto &port) {
return port.annotations.empty(); }) &&
2165 "class ports may not have annotations");
2167 buildClass<ClassOp>(builder, result, name, ports);
2170 auto *bodyRegion = result.regions[0].get();
2172 bodyRegion->push_back(body);
2175 for (
auto &elt : ports)
2176 body->addArgument(elt.type, elt.loc);
2179void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2180 ::mlir::OperationState &odsState, Twine name,
2181 mlir::ArrayRef<mlir::StringRef> fieldNames,
2182 mlir::ArrayRef<mlir::Type> fieldTypes) {
2184 SmallVector<PortInfo, 10> ports;
2185 ports.reserve(fieldNames.size() * 2);
2186 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2187 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2189 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2192 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2194 auto &body = odsState.regions[0]->getBlocks().front();
2195 auto prevLoc = odsBuilder.saveInsertionPoint();
2196 odsBuilder.setInsertionPointToEnd(&body);
2197 auto args = body.getArguments();
2198 auto loc = odsState.location;
2199 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2200 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2202 odsBuilder.restoreInsertionPoint(prevLoc);
2204void ClassOp::print(OpAsmPrinter &p) {
2208ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2209 auto hasSSAIdentifiers =
true;
2210 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2213LogicalResult ClassOp::verify() {
2215 auto type = operand.getType();
2216 if (!isa<PropertyType>(type)) {
2217 emitOpError(
"ports on a class must be properties");
2226ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2230void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2235SmallVector<PortInfo> ClassOp::getPorts() {
2236 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2239void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2240 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2244void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2245 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2248Convention ClassOp::getConvention() {
return Convention::Internal; }
2250ConventionAttr ClassOp::getConventionAttr() {
2251 return ConventionAttr::get(getContext(), getConvention());
2254ArrayAttr ClassOp::getParameters() {
return {}; }
2256ArrayAttr ClassOp::getPortAnnotationsAttr() {
2257 return ArrayAttr::get(getContext(), {});
2260ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2262void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2263 llvm_unreachable(
"classes do not support annotations");
2266ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2268ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2270SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2271 return ::getPortListImpl(*
this);
2275 return ::getPortImpl(*
this, idx);
2278BlockArgument ClassOp::getArgument(
size_t portNumber) {
2282bool ClassOp::canDiscardOnUseEmpty() {
2293void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2294 StringAttr name, ArrayRef<PortInfo> ports) {
2297 [](
const auto &port) {
return port.annotations.empty(); }) &&
2298 "class ports may not have annotations");
2299 buildClass<ExtClassOp>(builder, result, name, ports);
2302void ExtClassOp::print(OpAsmPrinter &p) {
2306ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2307 auto hasSSAIdentifiers =
false;
2308 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2312ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2316void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2321SmallVector<PortInfo> ExtClassOp::getPorts() {
2322 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2325void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2326 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2329void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2330 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2333Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2335ConventionAttr ExtClassOp::getConventionAttr() {
2336 return ConventionAttr::get(getContext(), getConvention());
2339ArrayAttr ExtClassOp::getLayersAttr() {
2340 return ArrayAttr::get(getContext(), {});
2343ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2345ArrayAttr ExtClassOp::getParameters() {
return {}; }
2347ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2348 return ArrayAttr::get(getContext(), {});
2351ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2353void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2354 llvm_unreachable(
"classes do not support annotations");
2357SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2358 return ::getPortListImpl(*
this);
2362 return ::getPortImpl(*
this, idx);
2365bool ExtClassOp::canDiscardOnUseEmpty() {
2376void InstanceOp::build(
2377 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2378 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2379 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2380 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2381 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2382 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2383 build(builder, result, resultTypes, moduleName, name, nameKind,
2384 portDirections, portNames, domainInfo, annotations, portAnnotations,
2385 layers, lowerToBind, doNotPrint,
2386 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2389void InstanceOp::build(
2390 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2391 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2392 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2393 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2394 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2395 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2396 result.addTypes(resultTypes);
2397 result.getOrAddProperties<Properties>().setModuleName(
2398 SymbolRefAttr::get(builder.getContext(), moduleName));
2399 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2400 result.getOrAddProperties<Properties>().setPortDirections(
2402 result.getOrAddProperties<Properties>().setPortNames(
2403 builder.getArrayAttr(portNames));
2405 if (domainInfo.empty()) {
2406 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2407 builder.getArrayAttr({}));
2408 result.getOrAddProperties<Properties>().setDomainInfo(
2409 builder.getArrayAttr(domainInfoVec));
2411 assert(domainInfo.size() == resultTypes.size());
2412 result.getOrAddProperties<Properties>().setDomainInfo(
2413 builder.getArrayAttr(domainInfo));
2416 result.getOrAddProperties<Properties>().setAnnotations(
2417 builder.getArrayAttr(annotations));
2418 result.getOrAddProperties<Properties>().setLayers(
2419 builder.getArrayAttr(layers));
2421 result.getOrAddProperties<Properties>().setLowerToBind(
2422 builder.getUnitAttr());
2424 result.getOrAddProperties<Properties>().setDoNotPrint(
2425 builder.getUnitAttr());
2427 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2429 result.getOrAddProperties<Properties>().setNameKind(
2430 NameKindEnumAttr::get(builder.getContext(), nameKind));
2432 if (portAnnotations.empty()) {
2433 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2434 builder.getArrayAttr({}));
2435 result.getOrAddProperties<Properties>().setPortAnnotations(
2436 builder.getArrayAttr(portAnnotationsVec));
2438 assert(portAnnotations.size() == resultTypes.size());
2439 result.getOrAddProperties<Properties>().setPortAnnotations(
2440 builder.getArrayAttr(portAnnotations));
2444void InstanceOp::build(OpBuilder &builder, OperationState &result,
2445 FModuleLike module, StringRef name,
2446 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2447 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2448 bool doNotPrint, hw::InnerSymAttr innerSym) {
2451 SmallVector<Type> resultTypes;
2452 resultTypes.reserve(module.getNumPorts());
2454 module.getPortTypes(), std::back_inserter(resultTypes),
2455 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2460 ArrayAttr portAnnotationsAttr;
2461 if (portAnnotations.empty()) {
2462 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2463 resultTypes.size(), builder.getArrayAttr({})));
2465 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2467 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2468 if (domainInfoAttr.empty()) {
2469 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2470 resultTypes.size(), builder.getArrayAttr({})));
2474 builder, result, resultTypes,
2475 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2476 builder.getStringAttr(name),
2477 NameKindEnumAttr::get(builder.getContext(), nameKind),
2478 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2479 builder.getArrayAttr(annotations), portAnnotationsAttr,
2480 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2481 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2484void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2485 ArrayRef<PortInfo> ports, StringRef moduleName,
2486 StringRef name, NameKindEnum nameKind,
2487 ArrayRef<Attribute> annotations,
2488 ArrayRef<Attribute> layers,
bool lowerToBind,
2489 bool doNotPrint, hw::InnerSymAttr innerSym) {
2491 SmallVector<Type> newResultTypes;
2492 SmallVector<Direction> newPortDirections;
2493 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2494 newResultTypes.reserve(ports.size());
2495 newPortDirections.reserve(ports.size());
2496 newPortNames.reserve(ports.size());
2497 newPortAnnotations.reserve(ports.size());
2498 newDomainInfo.reserve(ports.size());
2500 for (
auto &p : ports) {
2501 newResultTypes.push_back(p.type);
2502 newPortDirections.push_back(p.direction);
2503 newPortNames.push_back(p.name);
2504 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2506 newDomainInfo.push_back(p.domains);
2508 newDomainInfo.push_back(builder.getArrayAttr({}));
2511 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2512 newPortDirections, newPortNames, newDomainInfo, annotations,
2513 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2516LogicalResult InstanceOp::verify() {
2519 SmallVector<SymbolRefAttr> missingLayers;
2520 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2522 missingLayers.push_back(layer);
2524 if (missingLayers.empty())
2528 emitOpError(
"ambient layers are insufficient to instantiate module");
2529 auto ¬e = diag.attachNote();
2530 note <<
"missing layer requirements: ";
2531 interleaveComma(missingLayers, note);
2536 Operation *op1, Operation *op2,
2537 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2539 size_t n = insertions.size();
2540 size_t inserted = 0;
2541 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2542 while (inserted < n) {
2543 auto &[index, portInfo] = insertions[inserted];
2548 auto r1 = op1->getResult(i);
2549 auto r2 = op2->getResult(i + inserted);
2550 r1.replaceAllUsesWith(r2);
2555 const llvm::BitVector &erasures) {
2558 for (
size_t i = 0, e = op1->getNumResults(); i < e; ++i) {
2559 auto r1 = op1->getResult(i);
2561 assert(r1.use_empty() &&
"removed instance port has uses");
2565 auto r2 = op2->getResult(i - erased);
2566 r1.replaceAllUsesWith(r2);
2571InstanceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
2572 assert(erasures.size() >= getNumResults() &&
2573 "erasures is not at least as large as getNumResults()");
2575 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2576 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
2577 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2579 SmallVector<Attribute> newPortNames =
2581 SmallVector<Attribute> newPortAnnotations =
2583 ArrayAttr newDomainInfo =
2587 OpBuilder builder(*
this);
2588 auto clone = InstanceOp::create(
2589 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2590 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2591 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2592 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2594 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2595 clone->setAttr(
"output_file", outputFile);
2600FInstanceLike InstanceOp::cloneWithErasedPortsAndReplaceUses(
2601 const llvm::BitVector &erasures) {
2607ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2608 assert(portIdx < getNumResults() &&
2609 "index should be smaller than result number");
2610 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2613void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2614 assert(annotations.size() == getNumResults() &&
2615 "number of annotations is not equal to result number");
2616 (*this)->setAttr(
"portAnnotations",
2617 ArrayAttr::get(getContext(), annotations));
2620FInstanceLike InstanceOp::cloneWithInsertedPorts(
2621 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2625 auto oldPortCount = getNumResults();
2626 auto numInsertions = insertions.size();
2627 auto newPortCount = oldPortCount + numInsertions;
2629 SmallVector<Direction> newPortDirections;
2630 SmallVector<Attribute> newPortNames;
2631 SmallVector<Type> newPortTypes;
2632 SmallVector<Attribute> newPortAnnos;
2633 SmallVector<Attribute> newDomainInfo;
2635 newPortDirections.reserve(newPortCount);
2636 newPortNames.reserve(newPortCount);
2637 newPortTypes.reserve(newPortCount);
2638 newPortAnnos.reserve(newPortCount);
2639 newDomainInfo.reserve(newPortCount);
2645 SmallVector<unsigned> indexMap(oldPortCount);
2646 size_t inserted = 0;
2647 for (
size_t i = 0; i < oldPortCount; ++i) {
2648 while (inserted < numInsertions && insertions[inserted].first <= i)
2650 indexMap[i] = i + inserted;
2655 for (
size_t i = 0; i < oldPortCount; ++i) {
2656 while (inserted < numInsertions) {
2657 auto &[index,
info] = insertions[inserted];
2663 newPortDirections.push_back(
info.direction);
2664 newPortNames.push_back(
info.name);
2665 newPortTypes.push_back(
info.type);
2666 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2667 newDomainInfo.push_back(domains);
2671 newPortDirections.push_back(getPortDirection(i));
2672 newPortNames.push_back(getPortNameAttr(i));
2673 newPortTypes.push_back(getType(i));
2674 newPortAnnos.push_back(getPortAnnotation(i));
2677 newDomainInfo.push_back(domains);
2680 while (inserted < numInsertions) {
2681 auto &[index,
info] = insertions[inserted];
2684 newPortDirections.push_back(
info.direction);
2685 newPortNames.push_back(
info.name);
2686 newPortTypes.push_back(
info.type);
2687 newPortAnnos.push_back(
info.annotations.getArrayAttr());
2688 newDomainInfo.push_back(domains);
2692 OpBuilder builder(*
this);
2693 auto clone = InstanceOp::create(
2694 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2695 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2696 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2697 getDoNotPrint(), getInnerSymAttr());
2699 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2700 clone->setAttr(
"output_file", outputFile);
2705FInstanceLike InstanceOp::cloneWithInsertedPortsAndReplaceUses(
2706 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
2707 auto clone = cloneWithInsertedPorts(insertions);
2712LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2714 getModuleNameAttr());
2717StringRef InstanceOp::getInstanceName() {
return getName(); }
2719StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2721void InstanceOp::print(OpAsmPrinter &p) {
2724 p.printKeywordOrString(
getName());
2725 if (
auto attr = getInnerSymAttr()) {
2727 p.printSymbolName(attr.getSymName());
2729 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2730 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2733 SmallVector<StringRef, 10> omittedAttrs = {
2734 "moduleName",
"name",
"portDirections",
2735 "portNames",
"portTypes",
"portAnnotations",
2736 "inner_sym",
"nameKind",
"domainInfo"};
2737 if (getAnnotations().
empty())
2738 omittedAttrs.push_back(
"annotations");
2739 if (getLayers().
empty())
2740 omittedAttrs.push_back(
"layers");
2741 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2745 p.printSymbolName(getModuleName());
2748 SmallVector<Attribute> portTypes;
2749 portTypes.reserve(getNumResults());
2750 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2754 getPortNames().getValue(), portTypes,
2755 getPortAnnotations().getValue(), {}, {},
2756 getDomainInfo().getValue());
2759ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2760 auto *
context = parser.getContext();
2761 auto &properties = result.getOrAddProperties<Properties>();
2764 hw::InnerSymAttr innerSymAttr;
2765 FlatSymbolRefAttr moduleName;
2766 SmallVector<OpAsmParser::Argument> entryArgs;
2767 SmallVector<Direction, 4> portDirections;
2768 SmallVector<Attribute, 4> portNames;
2769 SmallVector<Attribute, 4> portTypes;
2770 SmallVector<Attribute, 4> portAnnotations;
2771 SmallVector<Attribute, 4> portSyms;
2772 SmallVector<Attribute, 4> portLocs;
2773 SmallVector<Attribute, 4> domains;
2774 NameKindEnumAttr nameKind;
2776 if (parser.parseKeywordOrString(&name))
2778 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2779 if (parser.parseCustomAttributeWithFallback(
2780 innerSymAttr, ::mlir::Type{},
2782 result.attributes)) {
2783 return ::mlir::failure();
2787 parser.parseOptionalAttrDict(result.attributes) ||
2788 parser.parseAttribute(moduleName) ||
2791 entryArgs, portDirections, portNames, portTypes,
2792 portAnnotations, portSyms, portLocs, domains))
2798 properties.setModuleName(moduleName);
2799 properties.setName(StringAttr::get(
context, name));
2800 properties.setNameKind(nameKind);
2801 properties.setPortDirections(
2803 properties.setPortNames(ArrayAttr::get(
context, portNames));
2804 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
2808 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2809 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2812 properties.setDomainInfo(ArrayAttr::get(
context, domains));
2815 result.types.reserve(portTypes.size());
2817 portTypes, std::back_inserter(result.types),
2818 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2823void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2828 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2829 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
2833std::optional<size_t> InstanceOp::getTargetResultIndex() {
2835 return std::nullopt;
2842void InstanceChoiceOp::build(
2843 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2844 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2845 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2846 ArrayRef<Attribute> portAnnotations, StringAttr innerSym,
2847 FlatSymbolRefAttr instanceMacro) {
2849 SmallVector<Type> resultTypes;
2850 for (Attribute portType : defaultModule.getPortTypes())
2851 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2854 ArrayAttr portAnnotationsAttr;
2855 if (portAnnotations.empty()) {
2856 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2857 resultTypes.size(), builder.getArrayAttr({})));
2859 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2863 ArrayAttr domainInfoAttr = defaultModule.getDomainInfoAttr();
2864 if (domainInfoAttr.empty()) {
2865 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2866 resultTypes.size(), builder.getArrayAttr({})));
2870 SmallVector<Attribute> moduleNames, caseNames;
2871 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2872 for (
auto [caseOption, caseModule] : cases) {
2873 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2874 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2875 {SymbolRefAttr::get(caseOption)}));
2876 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2879 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2880 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2881 NameKindEnumAttr::get(builder.getContext(), nameKind),
2882 defaultModule.getPortDirectionsAttr(),
2883 defaultModule.getPortNamesAttr(), domainInfoAttr,
2884 builder.getArrayAttr(annotations), portAnnotationsAttr,
2885 defaultModule.getLayersAttr(),
2886 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr(),
2890void InstanceChoiceOp::build(OpBuilder &builder, OperationState &odsState,
2891 ArrayRef<PortInfo> ports, ArrayAttr moduleNames,
2892 ArrayAttr caseNames, StringRef name,
2893 NameKindEnum nameKind, ArrayAttr annotations,
2894 ArrayAttr layers, hw::InnerSymAttr innerSym,
2895 FlatSymbolRefAttr instanceMacro) {
2897 SmallVector<Type> newResultTypes;
2898 SmallVector<bool> newPortDirections;
2899 SmallVector<Attribute> newPortNames, newPortAnnotations, newDomainInfo;
2900 newPortDirections.reserve(ports.size());
2901 newResultTypes.reserve(ports.size());
2902 newPortAnnotations.reserve(ports.size());
2903 newDomainInfo.reserve(ports.size());
2904 newPortNames.reserve(ports.size());
2905 for (
auto &p : ports) {
2906 newResultTypes.push_back(p.type);
2908 newPortDirections.push_back(p.direction == Direction::Out);
2909 newPortNames.push_back(p.name);
2910 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2912 newDomainInfo.push_back(p.domains);
2914 newDomainInfo.push_back(builder.getArrayAttr({}));
2917 return build(builder, odsState, newResultTypes, moduleNames, caseNames, name,
2918 nameKind, newPortDirections, builder.getArrayAttr(newPortNames),
2919 builder.getArrayAttr(newDomainInfo), annotations,
2920 builder.getArrayAttr(newPortAnnotations), layers.getValue(),
2921 innerSym, instanceMacro);
2924std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2925 return std::nullopt;
2928StringRef InstanceChoiceOp::getInstanceName() {
return getName(); }
2930StringAttr InstanceChoiceOp::getInstanceNameAttr() {
return getNameAttr(); }
2932ArrayAttr InstanceChoiceOp::getReferencedModuleNamesAttr() {
2934 auto moduleNames = getModuleNamesAttr();
2935 SmallVector<Attribute> moduleNameStrings;
2936 moduleNameStrings.reserve(moduleNames.size());
2937 for (
auto moduleName : moduleNames)
2938 moduleNameStrings.push_back(cast<FlatSymbolRefAttr>(moduleName).getAttr());
2940 return ArrayAttr::get(getContext(), moduleNameStrings);
2943void InstanceChoiceOp::print(OpAsmPrinter &p) {
2946 p.printKeywordOrString(
getName());
2947 if (
auto attr = getInnerSymAttr()) {
2949 p.printSymbolName(attr.getSymName());
2951 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2952 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2955 SmallVector<StringRef, 11> omittedAttrs = {
2956 "moduleNames",
"caseNames",
"name",
2957 "portDirections",
"portNames",
"portTypes",
2958 "portAnnotations",
"inner_sym",
"nameKind",
2960 if (getAnnotations().
empty())
2961 omittedAttrs.push_back(
"annotations");
2962 if (getLayers().
empty())
2963 omittedAttrs.push_back(
"layers");
2964 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2969 auto moduleNames = getModuleNamesAttr();
2970 auto caseNames = getCaseNamesAttr();
2972 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2974 p <<
" alternatives ";
2976 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2978 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2982 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2983 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2985 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2991 SmallVector<Attribute> portTypes;
2992 portTypes.reserve(getNumResults());
2993 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2996 getPortNames().getValue(), portTypes,
2997 getPortAnnotations().getValue(), {}, {},
2998 getDomainInfo().getValue());
3001ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
3002 OperationState &result) {
3003 auto *
context = parser.getContext();
3004 auto &properties = result.getOrAddProperties<Properties>();
3007 hw::InnerSymAttr innerSymAttr;
3008 SmallVector<Attribute> moduleNames;
3009 SmallVector<Attribute> caseNames;
3010 SmallVector<OpAsmParser::Argument> entryArgs;
3011 SmallVector<Direction, 4> portDirections;
3012 SmallVector<Attribute, 4> portNames;
3013 SmallVector<Attribute, 4> portTypes;
3014 SmallVector<Attribute, 4> portAnnotations;
3015 SmallVector<Attribute, 4> portSyms;
3016 SmallVector<Attribute, 4> portLocs;
3017 SmallVector<Attribute, 4> domains;
3018 NameKindEnumAttr nameKind;
3020 if (parser.parseKeywordOrString(&name))
3022 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3023 if (parser.parseCustomAttributeWithFallback(
3024 innerSymAttr, Type{},
3026 result.attributes)) {
3031 parser.parseOptionalAttrDict(result.attributes))
3034 FlatSymbolRefAttr defaultModuleName;
3035 if (parser.parseAttribute(defaultModuleName))
3037 moduleNames.push_back(defaultModuleName);
3041 FlatSymbolRefAttr optionName;
3042 if (parser.parseKeyword(
"alternatives") ||
3043 parser.parseAttribute(optionName) || parser.parseLBrace())
3046 FlatSymbolRefAttr moduleName;
3047 StringAttr caseName;
3048 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3049 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3051 moduleNames.push_back(moduleName);
3052 caseNames.push_back(SymbolRefAttr::get(
3053 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3054 if (failed(parser.parseOptionalComma()))
3057 if (parser.parseRBrace())
3063 entryArgs, portDirections, portNames, portTypes,
3064 portAnnotations, portSyms, portLocs, domains))
3069 properties.setModuleNames(ArrayAttr::get(
context, moduleNames));
3070 properties.setCaseNames(ArrayAttr::get(
context, caseNames));
3071 properties.setName(StringAttr::get(
context, name));
3072 properties.setNameKind(nameKind);
3073 properties.setPortDirections(
3075 properties.setPortNames(ArrayAttr::get(
context, portNames));
3076 properties.setDomainInfo(ArrayAttr::get(
context, domains));
3077 properties.setPortAnnotations(ArrayAttr::get(
context, portAnnotations));
3081 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3082 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3085 result.types.reserve(portTypes.size());
3087 portTypes, std::back_inserter(result.types),
3088 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3093void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3095 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3096 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3099LogicalResult InstanceChoiceOp::verify() {
3100 if (getCaseNamesAttr().
empty())
3101 return emitOpError() <<
"must have at least one case";
3102 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3103 return emitOpError() <<
"number of referenced modules does not match the "
3104 "number of options";
3109 SmallVector<SymbolRefAttr> missingLayers;
3110 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3112 missingLayers.push_back(layer);
3114 if (missingLayers.empty())
3118 emitOpError(
"ambient layers are insufficient to instantiate module");
3119 auto ¬e = diag.attachNote();
3120 note <<
"missing layer requirements: ";
3121 interleaveComma(missingLayers, note);
3126InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3127 auto caseNames = getCaseNamesAttr();
3128 for (
auto moduleName : getModuleNamesAttr()) {
3129 auto moduleNameRef = cast<FlatSymbolRefAttr>(moduleName);
3135 auto referencedModule =
3136 symbolTable.lookupNearestSymbolFrom<FModuleLike>(*
this, moduleNameRef);
3137 if (isa<FIntModuleOp>(referencedModule))
3138 return emitOpError(
"intmodule must be instantiated with instance op, "
3139 "not via 'firrtl.instance_choice'");
3142 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3143 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3144 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3145 auto refRoot = ref.getRootReference();
3146 if (ref.getRootReference() != root)
3147 return emitOpError() <<
"case " << ref
3148 <<
" is not in the same option group as "
3151 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3152 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3154 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3155 return emitOpError() <<
"option " << refRoot
3156 <<
" does not contain option case " << ref;
3159 if (
auto instanceMacro = getInstanceMacroAttr())
3160 if (!symbolTable.lookupNearestSymbolFrom(*
this, instanceMacro))
3161 return emitOpError() <<
"instance_macro " << instanceMacro
3162 <<
" does not exist";
3168InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3169 auto caseNames = getCaseNamesAttr();
3170 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3171 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3172 if (caseSym == option.getSymName())
3173 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3175 return getDefaultTargetAttr();
3178SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3179InstanceChoiceOp::getTargetChoices() {
3180 auto caseNames = getCaseNamesAttr();
3181 auto moduleNames = getModuleNamesAttr();
3182 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3183 for (
size_t i = 0; i < caseNames.size(); ++i) {
3184 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3185 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3191FInstanceLike InstanceChoiceOp::cloneWithInsertedPorts(
3192 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3196 auto oldPortCount = getNumResults();
3197 auto numInsertions = insertions.size();
3198 auto newPortCount = oldPortCount + numInsertions;
3200 SmallVector<Direction> newPortDirections;
3201 SmallVector<Attribute> newPortNames;
3202 SmallVector<Type> newPortTypes;
3203 SmallVector<Attribute> newPortAnnos;
3204 SmallVector<Attribute> newDomainInfo;
3206 newPortDirections.reserve(newPortCount);
3207 newPortNames.reserve(newPortCount);
3208 newPortTypes.reserve(newPortCount);
3209 newPortAnnos.reserve(newPortCount);
3210 newDomainInfo.reserve(newPortCount);
3216 SmallVector<unsigned> indexMap(oldPortCount);
3217 size_t inserted = 0;
3218 for (
size_t i = 0; i < oldPortCount; ++i) {
3219 while (inserted < numInsertions && insertions[inserted].first <= i)
3221 indexMap[i] = i + inserted;
3226 for (
size_t i = 0; i < oldPortCount; ++i) {
3227 while (inserted < numInsertions) {
3228 auto &[index,
info] = insertions[inserted];
3234 newPortDirections.push_back(
info.direction);
3235 newPortNames.push_back(
info.name);
3236 newPortTypes.push_back(
info.type);
3237 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3238 newDomainInfo.push_back(domains);
3242 newPortDirections.push_back(getPortDirection(i));
3243 newPortNames.push_back(getPortNameAttr(i));
3244 newPortTypes.push_back(getType(i));
3245 newPortAnnos.push_back(getPortAnnotations()[i]);
3248 newDomainInfo.push_back(domains);
3251 while (inserted < numInsertions) {
3252 auto &[index,
info] = insertions[inserted];
3255 newPortDirections.push_back(
info.direction);
3256 newPortNames.push_back(
info.name);
3257 newPortTypes.push_back(
info.type);
3258 newPortAnnos.push_back(
info.annotations.getArrayAttr());
3259 newDomainInfo.push_back(domains);
3263 OpBuilder builder(*
this);
3264 auto clone = InstanceChoiceOp::create(
3265 builder,
getLoc(), newPortTypes, getModuleNames(), getCaseNames(),
3268 ArrayAttr::get(
context, newPortNames),
3269 ArrayAttr::get(
context, newDomainInfo), getAnnotationsAttr(),
3270 ArrayAttr::get(
context, newPortAnnos), getLayers(), getInnerSymAttr(),
3271 getInstanceMacroAttr());
3273 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3274 clone->setAttr(
"output_file", outputFile);
3279FInstanceLike InstanceChoiceOp::cloneWithInsertedPortsAndReplaceUses(
3280 ArrayRef<std::pair<unsigned, PortInfo>> insertions) {
3281 auto clone = cloneWithInsertedPorts(insertions);
3287InstanceChoiceOp::cloneWithErasedPorts(
const llvm::BitVector &erasures) {
3288 assert(erasures.size() >= getNumResults() &&
3289 "erasures is not at least as large as getNumResults()");
3291 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3292 SmallVector<Type>(result_type_begin(), result_type_end()), erasures);
3293 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3295 SmallVector<Attribute> newPortNames =
3297 SmallVector<Attribute> newPortAnnotations =
3299 ArrayAttr newPortDomains =
3303 OpBuilder builder(*
this);
3304 auto clone = InstanceChoiceOp::create(
3305 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3308 ArrayAttr::get(getContext(), newPortNames), newPortDomains,
3309 getAnnotationsAttr(), ArrayAttr::get(getContext(), newPortAnnotations),
3310 getLayers(), getInnerSymAttr(), getInstanceMacroAttr());
3312 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3313 clone->setAttr(
"output_file", outputFile);
3318FInstanceLike InstanceChoiceOp::cloneWithErasedPortsAndReplaceUses(
3319 const llvm::BitVector &erasures) {
3329ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3330 assert(portIdx < getNumResults() &&
3331 "index should be smaller than result number");
3332 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3335void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3336 assert(annotations.size() == getNumResults() &&
3337 "number of annotations is not equal to result number");
3338 (*this)->setAttr(
"portAnnotations",
3339 ArrayAttr::get(getContext(), annotations));
3343void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3344 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3347 numReadWritePorts = 0;
3349 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3350 auto portKind = getPortKind(i);
3351 if (portKind == MemOp::PortKind::Debug)
3353 else if (portKind == MemOp::PortKind::Read)
3355 else if (portKind == MemOp::PortKind::Write) {
3358 ++numReadWritePorts;
3363LogicalResult MemOp::verify() {
3367 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3373 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3374 auto portName = getPortNameAttr(i);
3379 BundleType portBundleType =
3380 type_dyn_cast<BundleType>(getResult(i).getType());
3383 if (!portNamesSet.insert(portName).second) {
3384 emitOpError() <<
"has non-unique port name " << portName;
3392 auto elt = getPortNamed(portName);
3394 emitOpError() <<
"could not get port with name " << portName;
3397 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3400 if (portKind == MemOp::PortKind::Debug &&
3401 !type_isa<RefType>(getResult(i).getType()))
3402 return emitOpError() <<
"has an invalid type on port " << portName
3403 <<
" (expected Read/Write/ReadWrite/Debug)";
3404 if (type_isa<RefType>(firrtlType) && e == 1)
3405 return emitOpError()
3406 <<
"cannot have only one port of debug type. Debug port can only "
3407 "exist alongside other read/write/read-write port";
3412 if (portKind == MemOp::PortKind::Debug) {
3413 auto resType = type_cast<RefType>(getResult(i).getType());
3414 if (!(resType && type_isa<FVectorType>(resType.getType())))
3415 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3416 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3418 auto dataTypeOption = portBundleType.getElement(
"data");
3419 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3420 dataTypeOption = portBundleType.getElement(
"wdata");
3421 if (!dataTypeOption) {
3422 emitOpError() <<
"has no data field on port " << portName
3423 <<
" (expected to see \"data\" for a read or write "
3424 "port or \"rdata\" for a read/write port)";
3427 dataType = dataTypeOption->type;
3429 if (portKind == MemOp::PortKind::Read) {
3436 emitOpError() <<
"has non-passive data type on port " << portName
3437 <<
" (memory types must be passive)";
3442 if (dataType.containsAnalog()) {
3443 emitOpError() <<
"has a data type that contains an analog type on port "
3445 <<
" (memory types cannot contain analog types)";
3453 getTypeForPort(getDepth(), dataType, portKind,
3454 dataType.isGround() ? getMaskBits() : 0);
3457 auto originalType = getResult(i).getType();
3458 if (originalType != expectedType) {
3459 StringRef portKindName;
3461 case MemOp::PortKind::Read:
3462 portKindName =
"read";
3464 case MemOp::PortKind::Write:
3465 portKindName =
"write";
3467 case MemOp::PortKind::ReadWrite:
3468 portKindName =
"readwrite";
3470 case MemOp::PortKind::Debug:
3471 portKindName =
"dbg";
3474 emitOpError() <<
"has an invalid type for port " << portName
3475 <<
" of determined kind \"" << portKindName
3476 <<
"\" (expected " << expectedType <<
", but got "
3477 << originalType <<
")";
3483 if (oldDataType && oldDataType != dataType) {
3484 emitOpError() <<
"port " << getPortNameAttr(i)
3485 <<
" has a different type than port "
3486 << getPortNameAttr(i - 1) <<
" (expected " << oldDataType
3487 <<
", but got " << dataType <<
")";
3491 oldDataType = dataType;
3494 auto maskWidth = getMaskBits();
3496 auto dataWidth = getDataType().getBitWidthOrSentinel();
3497 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3498 return emitOpError(
"the mask width cannot be greater than "
3501 if (getPortAnnotations().size() != getNumResults())
3502 return emitOpError(
"the number of result annotations should be "
3503 "equal to the number of results");
3509 return std::max(1U, llvm::Log2_64_Ceil(depth));
3515 PortKind portKind,
size_t maskBits) {
3517 auto *
context = dataType.getContext();
3518 if (portKind == PortKind::Debug)
3519 return RefType::get(FVectorType::get(dataType, depth));
3525 maskType = UIntType::get(
context, maskBits);
3527 auto getId = [&](StringRef name) -> StringAttr {
3528 return StringAttr::get(
context, name);
3531 SmallVector<BundleType::BundleElement, 7> portFields;
3535 portFields.push_back({getId(
"addr"),
false, addressType});
3536 portFields.push_back({getId(
"en"),
false, UIntType::get(
context, 1)});
3537 portFields.push_back({getId(
"clk"),
false, ClockType::get(
context)});
3540 case PortKind::Read:
3541 portFields.push_back({getId(
"data"),
true, dataType});
3544 case PortKind::Write:
3545 portFields.push_back({getId(
"data"),
false, dataType});
3546 portFields.push_back({getId(
"mask"),
false, maskType});
3549 case PortKind::ReadWrite:
3550 portFields.push_back({getId(
"rdata"),
true, dataType});
3551 portFields.push_back({getId(
"wmode"),
false, UIntType::get(
context, 1)});
3552 portFields.push_back({getId(
"wdata"),
false, dataType});
3553 portFields.push_back({getId(
"wmask"),
false, maskType});
3556 llvm::report_fatal_error(
"memory port kind not handled");
3560 return BundleType::get(
context, portFields);
3564SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3565 SmallVector<MemOp::NamedPort> result;
3567 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3569 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3576MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3578 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3582MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3584 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3588size_t MemOp::getMaskBits() {
3590 for (
auto res : getResults()) {
3591 if (type_isa<RefType>(res.getType()))
3593 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3600 if (t.name.getValue().contains(
"mask"))
3603 if (type_isa<UIntType>(mType))
3613 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3615 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3616 return type_cast<FVectorType>(refType.getType()).getElementType();
3617 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3619 StringRef dataFieldName =
"data";
3621 dataFieldName =
"rdata";
3623 return type_cast<BundleType>(firstPortType.getPassiveType())
3624 .getElementType(dataFieldName);
3627StringAttr MemOp::getPortNameAttr(
size_t resultNo) {
3628 return cast<StringAttr>(getPortNames()[resultNo]);
3632 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3635Value MemOp::getPortNamed(StringAttr name) {
3636 auto namesArray = getPortNames();
3637 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3638 if (namesArray[i] == name) {
3639 assert(i < getNumResults() &&
" names array out of sync with results");
3640 return getResult(i);
3649 size_t numReadPorts = 0;
3650 size_t numWritePorts = 0;
3651 size_t numReadWritePorts = 0;
3653 SmallVector<int32_t> writeClockIDs;
3655 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3656 auto portKind = op.getPortKind(i);
3657 if (portKind == MemOp::PortKind::Read)
3659 else if (portKind == MemOp::PortKind::Write) {
3660 for (
auto *a : op.getResult(i).getUsers()) {
3661 auto subfield = dyn_cast<SubfieldOp>(a);
3662 if (!subfield || subfield.getFieldIndex() != 2)
3664 auto clockPort = a->getResult(0);
3665 for (
auto *b : clockPort.getUsers()) {
3666 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3667 if (
connect.getDest() == clockPort) {
3670 connect.getSrc(),
true,
true,
true),
3672 if (result.second) {
3673 writeClockIDs.push_back(numWritePorts);
3675 writeClockIDs.push_back(result.first->second);
3684 ++numReadWritePorts;
3691 op.emitError(
"'firrtl.mem' should have simple type and known width");
3692 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3694 if (op->hasAttr(
"modName"))
3695 modName = op->getAttrOfType<StringAttr>(
"modName");
3697 SmallString<8> clocks;
3698 for (
auto a : writeClockIDs)
3699 clocks.
append(Twine((char)(a +
'a')).str());
3700 SmallString<32> initStr;
3705 for (
auto c : init.getFilename().getValue())
3706 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3707 (c >=
'0' && c <=
'9'))
3708 initStr.push_back(c);
3709 initStr.push_back(
'_');
3710 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3711 initStr.push_back(
'_');
3712 initStr.push_back(init.getIsInline() ?
't' :
'f');
3714 modName = StringAttr::get(
3717 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3718 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3719 numReadWritePorts, (
size_t)width, op.getDepth(),
3720 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3721 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3722 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3724 return {numReadPorts,
3729 op.getReadLatency(),
3730 op.getWriteLatency(),
3732 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3733 seq::WUW::PortOrder,
3736 op.getMaskBits() > 1,
3742void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3747 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3748 setNameFn(getResult(i), (base +
"_" + getPortName(i)).str());
3752std::optional<size_t> MemOp::getTargetResultIndex() {
3754 return std::nullopt;
3762 OpAsmSetValueNameFn setNameFn) {
3765 setNameFn(op.getDataRaw(), name);
3766 if (op.isForceable())
3767 setNameFn(op.getDataRef(), (name +
"_ref").str());
3770void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3774LogicalResult NodeOp::inferReturnTypes(
3775 mlir::MLIRContext *
context, std::optional<mlir::Location> location,
3776 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3777 ::mlir::PropertyRef properties, ::mlir::RegionRange regions,
3778 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3779 if (operands.empty())
3781 Adaptor adaptor(operands, attributes, properties, regions);
3782 inferredReturnTypes.push_back(adaptor.getInput().getType());
3783 if (adaptor.getForceable()) {
3785 true, adaptor.getInput().getType());
3786 if (!forceableType) {
3788 ::mlir::emitError(*location,
"cannot force a node of type ")
3789 << operands[0].getType();
3792 inferredReturnTypes.push_back(forceableType);
3797std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3799void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3803std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3805SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3806RegOp::computeDataFlow() {
3815 IntegerAttr initial) {
3820 auto intType = type_dyn_cast<IntType>(regType);
3822 return op->emitError(
3823 "'initial' value is only supported on ground-type registers");
3826 auto width = intType.getWidthOrSentinel();
3827 if (width != -1 && (
int)initial.getValue().getBitWidth() != width)
3828 return op->emitError(
"'initial' value bitwidth (")
3829 << initial.getValue().getBitWidth()
3830 <<
") doesn't match register type width (" << width <<
")";
3833 auto attrType = type_cast<IntegerType>(initial.getType());
3834 if (attrType.isSignless() || attrType.isSigned() != intType.isSigned())
3835 return op->emitError(
"'initial' value has wrong sign");
3840LogicalResult RegOp::verify() {
3844LogicalResult RegResetOp::verify() {
3845 auto reset = getResetValue();
3852 return emitError(
"type mismatch between register ")
3853 << regType <<
" and reset value " << resetType;
3858std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3860void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3869FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3870 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3872 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3874 if (!isa<FModuleLike>(op)) {
3875 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3876 <<
" is not a module";
3877 d.attachNote(op->getLoc()) <<
"target defined here";
3889SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3890 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3892 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3894 auto complain = [&] {
3895 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3896 d.attachNote(op->getLoc()) <<
"target defined here";
3900 auto module = dyn_cast<FModuleLike>(op);
3902 return complain() <<
"is not a module";
3904 auto numPorts =
module.getNumPorts();
3906 return complain() <<
"must have at least 4 ports, got " << numPorts
3910 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3911 llvm::function_ref<bool(Type)> checkType,
3912 StringRef expType) {
3913 auto name =
module.getPortNameAttr(idx);
3914 if (name != expName) {
3915 complain() <<
"port " << idx <<
" must be called \"" << expName
3916 <<
"\", got " << name <<
" instead";
3919 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3923 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3924 <<
", got " << stringify(dir) <<
" instead";
3927 if (
auto type = module.getPortType(idx); !checkType(type)) {
3928 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3929 <<
"', got " << type <<
" instead";
3935 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3936 auto isBool = [](Type type) {
3937 if (
auto uintType = dyn_cast<UIntType>(type))
3938 return uintType.getWidth() == 1;
3942 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3949 for (
unsigned i = 4; i < numPorts; ++i) {
3950 auto type =
module.getPortType(i);
3951 auto firrtlType = type_dyn_cast<FIRRTLType>(type);
3953 return complain() <<
"port " << i <<
" contains hardware types: " << type;
3963void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3967SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3968RegResetOp::computeDataFlow() {
3973std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3975LogicalResult WireOp::verify() {
3977 if (type_isa<DomainType>(getResult().getType()) && !getDomains().
empty())
3978 return emitOpError(
"of domain type must not have domain associations");
3981 auto domains = getDomains();
3982 if (!domains.size())
3995 using oldValueAndDiag = std::pair<Value, std::unique_ptr<InFlightDiagnostic>>;
3997 bool hasErrors =
false;
3998 for (
auto domain : domains) {
3999 auto domainType = cast<DomainType>(domain.getType());
4000 auto domainName = domainType.getName();
4003 auto [it, inserted] =
4004 domainInfo.try_emplace(domainName, std::make_pair(domain,
nullptr));
4011 auto &[value, diag] = it->second;
4017 diag = std::make_unique<InFlightDiagnostic>(
4018 emitOpError() <<
"associated with multiple operands of '"
4019 << domainName.getValue() <<
"' kind");
4020 diag->attachNote(value.getLoc()) <<
"first domain operand here";
4025 diag->attachNote(domain.getLoc())
4026 <<
"additional colliding domain operand here";
4038 for (
auto &[_, diag] : domainInfo.values())
4044LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4045 if (
auto refType = type_dyn_cast<RefType>(getType(0)))
4047 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4048 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4050 if (
auto domainType = type_dyn_cast<DomainType>(getType(0)))
4051 return domainType.verifySymbolUses(getOperation(), symbolTable);
4060LogicalResult ContractOp::verify() {
4061 if (getBody().getArgumentTypes() != getInputs().getType())
4062 return emitOpError(
"result types and region argument types must match");
4071OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4072 auto caseMacro = getCaseMacroAttr();
4077 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4078 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4080 return emitOpError(
"case_macro references an undefined symbol: ")
4083 if (!isa<sv::MacroDeclOp>(refOp))
4084 return emitOpError(
"case_macro must reference a macro declaration");
4093void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4095 build(builder, state, klass.getInstanceType(),
4096 StringAttr::get(builder.getContext(), name));
4099LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4100 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4101 auto classType = getType();
4102 auto className = classType.getNameAttr();
4105 auto classOp = dyn_cast_or_null<ClassLike>(
4106 symbolTable.lookupSymbolIn(circuitOp, className));
4108 return emitOpError() <<
"references unknown class " << className;
4111 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4117StringAttr ObjectOp::getClassNameAttr() {
4118 return getType().getNameAttr().getAttr();
4121StringRef ObjectOp::getClassName() {
return getType().getName(); }
4123ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4124 auto symRef = getType().getNameAttr();
4125 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4128Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4129 return getReferencedClass(symtbl);
4132StringRef ObjectOp::getInstanceName() {
return getName(); }
4134StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4136StringAttr ObjectOp::getReferencedModuleNameAttr() {
4137 return getClassNameAttr();
4140void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4141 setNameFn(getResult(),
getName());
4148LogicalResult AttachOp::verify() {
4150 std::optional<int32_t> commonWidth;
4151 for (
auto operand : getOperands()) {
4152 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4156 commonWidth = thisWidth;
4159 if (commonWidth != thisWidth)
4160 return emitOpError(
"is inavlid as not all known operand widths match");
4167 Value dst = connect->getOperand(0);
4168 Value src = connect->getOperand(1);
4177 if (isa<PropertyType>(src.getType()) ||
4181 auto diag = emitError(connect->getLoc());
4182 diag <<
"connect has invalid flow: the source expression ";
4184 diag <<
"\"" << srcName <<
"\" ";
4185 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4186 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4194 auto diag = emitError(connect->getLoc());
4195 diag <<
"connect has invalid flow: the destination expression ";
4197 diag <<
"\"" << dstName <<
"\" ";
4198 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4199 return diag.attachNote(dstRef.getLoc())
4200 <<
"the destination was defined here";
4209 bool outerTypeIsConst =
false) {
4210 auto typeIsConst = outerTypeIsConst || type.
isConst();
4215 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4216 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4217 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4221 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4233 auto dest = connect.getDest();
4234 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4235 auto src = connect.getSrc();
4236 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4237 if (!destType || !srcType)
4240 auto destRefinedType = destType;
4241 auto srcRefinedType = srcType;
4246 auto findFieldDeclarationRefiningFieldType =
4248 while (
auto *definingOp = value.getDefiningOp()) {
4249 bool shouldContinue =
true;
4250 TypeSwitch<Operation *>(definingOp)
4251 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4252 .Case<SubaccessOp>([&](SubaccessOp op) {
4256 .getElementTypePreservingConst()
4258 originalFieldType = originalFieldType.getConstType(
true);
4259 value = op.getInput();
4261 .Default([&](Operation *) { shouldContinue =
false; });
4262 if (!shouldContinue)
4268 auto destDeclaration =
4269 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4270 auto srcDeclaration =
4271 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4273 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4274 Value declaration) -> LogicalResult {
4275 auto *declarationBlock = declaration.getParentBlock();
4276 auto *block = connect->getBlock();
4277 while (block && block != declarationBlock) {
4278 auto *parentOp = block->getParentOp();
4280 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4281 whenOp && !whenOp.getCondition().getType().isConst()) {
4283 return connect.emitOpError()
4284 <<
"assignment to 'const' type " << type
4285 <<
" is dependent on a non-'const' condition";
4286 return connect->emitOpError()
4287 <<
"assignment to nested 'const' member of type " << type
4288 <<
" is dependent on a non-'const' condition";
4291 block = parentOp->getBlock();
4296 auto emitSubaccessError = [&] {
4297 return connect.emitError(
4298 "assignment to non-'const' subaccess of 'const' type is disallowed");
4304 if (destType != destRefinedType)
4305 return emitSubaccessError();
4307 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4312 if (srcRefinedType.containsConst() &&
4315 if (srcType != srcRefinedType)
4316 return emitSubaccessError();
4317 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4334 auto dest = connect.getDest();
4335 for (
auto *user : dest.getUsers()) {
4336 if (
auto c = dyn_cast<FConnectLike>(user);
4337 c && c.getDest() == dest && c != connect) {
4338 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4340 diag.attachNote(c->getLoc()) <<
"other driver is here";
4347LogicalResult ConnectOp::verify() {
4348 auto dstType = getDest().getType();
4349 auto srcType = getSrc().getType();
4350 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4351 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4352 if (!dstBaseType || !srcBaseType) {
4353 if (dstType != srcType)
4354 return emitError(
"may not connect different non-base types");
4357 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4358 return emitError(
"analog types may not be connected");
4362 return emitError(
"type mismatch between destination ")
4363 << dstBaseType <<
" and source " << srcBaseType;
4368 return emitError(
"destination ")
4369 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4382LogicalResult MatchingConnectOp::verify() {
4383 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4384 auto baseType = type_cast<FIRRTLBaseType>(type);
4387 if (baseType && baseType.containsAnalog())
4388 return emitError(
"analog types may not be connected");
4393 "`SameAnonTypeOperands` trait should have already rejected "
4394 "structurally non-equivalent types");
4407LogicalResult RefDefineOp::verify() {
4414 if (
auto *op = getDest().getDefiningOp()) {
4416 if (isa<RefSubOp>(op))
4418 "destination reference cannot be a sub-element of a reference");
4419 if (isa<RefCastOp>(op))
4421 "destination reference cannot be a cast of another reference");
4429 SmallVector<SymbolRefAttr> missingLayers;
4432 "has more layer requirements than destination",
4433 "additional layers required");
4436LogicalResult PropAssignOp::verify() {
4446LogicalResult PropertyAssertOp::verify() {
4449 if (
auto *defOp = getCondition().getDefiningOp())
4450 if (
auto boolConst = dyn_cast<BoolConstantOp>(defOp))
4451 if (!boolConst.getValue())
4452 return emitOpError(
"property assertion is statically false");
4457 auto domainType = dyn_cast<DomainType>(value.getType());
4462 return domainType.getName();
4465LogicalResult DomainDefineOp::verify() {
4472 auto dst = getDest();
4473 auto src = getSrc();
4481 if (
auto *srcDefOp = src.getDefiningOp())
4482 if (isa<WireOp>(srcDefOp))
4484 if (
auto *dstDefOp = dst.getDefiningOp())
4485 if (isa<WireOp>(dstDefOp))
4490 return emitError(
"could not determine domain-type of destination");
4494 return emitError(
"could not determine domain-type of source");
4496 if (dstDomain != srcDomain) {
4497 auto diag = emitError()
4498 <<
"source domain type " << srcDomain
4499 <<
" does not match destination domain type " << dstDomain;
4506void WhenOp::createElseRegion() {
4507 assert(!hasElseRegion() &&
"already has an else region");
4508 getElseRegion().push_back(
new Block());
4511void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4512 bool withElseRegion, std::function<
void()> thenCtor,
4513 std::function<
void()> elseCtor) {
4514 OpBuilder::InsertionGuard guard(builder);
4515 result.addOperands(condition);
4518 builder.createBlock(result.addRegion());
4523 Region *elseRegion = result.addRegion();
4524 if (withElseRegion) {
4525 builder.createBlock(elseRegion);
4535LogicalResult MatchOp::verify() {
4536 FEnumType type = getInput().getType();
4539 auto numCases = getTags().size();
4540 auto numRegions = getNumRegions();
4541 if (numRegions != numCases)
4542 return emitOpError(
"expected ")
4543 << numRegions <<
" tags but got " << numCases;
4545 auto numTags = type.getNumElements();
4547 SmallDenseSet<int64_t> seen;
4548 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4549 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4552 if (region.getNumArguments() != 1)
4553 return emitOpError(
"region should have exactly one argument");
4556 if (tagIndex >= numTags)
4557 return emitOpError(
"the tag index ")
4558 << tagIndex <<
" is out of the range of valid tags in " << type;
4561 auto [it, inserted] = seen.insert(tagIndex);
4563 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4564 <<
" is matched more than once";
4567 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4568 auto regionType = region.getArgument(0).getType();
4569 if (regionType != expectedType)
4570 return emitOpError(
"region type ")
4571 << regionType <<
" does not match the expected type "
4576 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4577 if (!seen.contains(i))
4578 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4583void MatchOp::print(OpAsmPrinter &p) {
4584 auto input = getInput();
4585 FEnumType type = input.getType();
4586 auto regions = getRegions();
4587 p <<
" " << input <<
" : " << type;
4588 SmallVector<StringRef> elided = {
"tags"};
4589 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4592 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4595 p.printKeywordOrString(
4596 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4598 p.printRegionArgument(region.front().getArgument(0), {},
4601 p.printRegion(region,
false);
4608ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4609 auto *
context = parser.getContext();
4610 auto &properties = result.getOrAddProperties<Properties>();
4611 OpAsmParser::UnresolvedOperand input;
4612 if (parser.parseOperand(input) || parser.parseColon())
4615 auto loc = parser.getCurrentLocation();
4617 if (parser.parseType(type))
4619 auto enumType = type_dyn_cast<FEnumType>(type);
4621 return parser.emitError(loc,
"expected enumeration type but got") << type;
4623 if (parser.resolveOperand(input, type, result.operands) ||
4624 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4625 parser.parseLBrace())
4628 auto i32Type = IntegerType::get(
context, 32);
4629 SmallVector<Attribute> tags;
4632 if (failed(parser.parseOptionalKeyword(
"case")))
4636 auto nameLoc = parser.getCurrentLocation();
4638 OpAsmParser::Argument arg;
4639 auto *region = result.addRegion();
4640 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4641 parser.parseArgument(arg) || parser.parseRParen())
4645 auto index = enumType.getElementIndex(name);
4647 return parser.emitError(nameLoc,
"the tag \"")
4648 << name <<
"\" is not a member of the enumeration " << enumType;
4649 tags.push_back(IntegerAttr::get(i32Type, *index));
4652 arg.type = enumType.getElementTypePreservingConst(*index);
4653 if (parser.parseRegion(*region, arg))
4656 properties.setTags(ArrayAttr::get(
context, tags));
4658 return parser.parseRBrace();
4661void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4663 MutableArrayRef<std::unique_ptr<Region>> regions) {
4664 auto &properties = result.getOrAddProperties<Properties>();
4665 result.addOperands(input);
4666 properties.setTags(tags);
4667 result.addRegions(regions);
4676 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4677 bool visitInvalidExpr(Operation *op) {
return false; }
4678 bool visitUnhandledExpr(Operation *op) {
return true; }
4684void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4687 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4688 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4689 auto width = ty.getWidthOrSentinel();
4693 name = (Twine(base) + Twine(width)).str();
4694 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4695 auto width = ty.getWidthOrSentinel();
4697 name =
"invalid_analog";
4699 name = (
"invalid_analog" + Twine(width)).str();
4700 }
else if (type_isa<AsyncResetType>(getType()))
4701 name =
"invalid_asyncreset";
4702 else if (type_isa<ResetType>(getType()))
4703 name =
"invalid_reset";
4704 else if (type_isa<ClockType>(getType()))
4705 name =
"invalid_clock";
4709 setNameFn(getResult(), name);
4712void ConstantOp::print(OpAsmPrinter &p) {
4714 p.printAttributeWithoutType(getValueAttr());
4716 p.printType(getType());
4717 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4720ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4721 auto &properties = result.getOrAddProperties<Properties>();
4724 auto loc = parser.getCurrentLocation();
4725 auto valueResult = parser.parseOptionalInteger(value);
4726 if (!valueResult.has_value())
4727 return parser.emitError(loc,
"expected integer value");
4731 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4732 parser.parseOptionalAttrDict(result.attributes))
4734 result.addTypes(resultType);
4740 if (width > value.getBitWidth()) {
4744 value = value.sext(width);
4745 }
else if (width < value.getBitWidth()) {
4748 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4749 : value.getActiveBits();
4750 if (width < neededBits)
4751 return parser.emitError(loc,
"constant out of range for result type ")
4753 value = value.trunc(width);
4757 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4759 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4760 properties.setValue(valueAttr);
4764LogicalResult ConstantOp::verify() {
4768 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4770 "firrtl.constant attribute bitwidth doesn't match return type");
4773 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4774 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4775 return emitError(
"firrtl.constant attribute has wrong sign");
4782void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4783 const APInt &value) {
4786 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4787 "incorrect attribute bitwidth for firrtl.constant");
4790 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4791 return build(builder, result, type, attr);
4796void ConstantOp::build(OpBuilder &builder, OperationState &result,
4797 const APSInt &value) {
4798 auto attr = IntegerAttr::get(builder.getContext(), value);
4800 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4801 return build(builder, result, type, attr);
4804void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4811 SmallString<32> specialNameBuffer;
4812 llvm::raw_svector_ostream specialName(specialNameBuffer);
4814 getValue().print(specialName, intTy.
isSigned());
4816 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4819 specialName << width;
4820 setNameFn(getResult(), specialName.str());
4823void SpecialConstantOp::print(OpAsmPrinter &p) {
4826 p << static_cast<unsigned>(getValue());
4828 p.printType(getType());
4829 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4832ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4833 OperationState &result) {
4834 auto &properties = result.getOrAddProperties<Properties>();
4838 auto loc = parser.getCurrentLocation();
4839 auto valueResult = parser.parseOptionalInteger(value);
4840 if (!valueResult.has_value())
4841 return parser.emitError(loc,
"expected integer value");
4844 if (value != 0 && value != 1)
4845 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4849 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4850 parser.parseOptionalAttrDict(result.attributes))
4852 result.addTypes(resultType);
4855 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4856 properties.setValue(valueAttr);
4860void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4861 SmallString<32> specialNameBuffer;
4862 llvm::raw_svector_ostream specialName(specialNameBuffer);
4864 specialName << static_cast<unsigned>(getValue());
4865 auto type = getType();
4866 if (type_isa<ClockType>(type)) {
4867 specialName <<
"_clock";
4868 }
else if (type_isa<ResetType>(type)) {
4869 specialName <<
"_reset";
4870 }
else if (type_isa<AsyncResetType>(type)) {
4871 specialName <<
"_asyncreset";
4873 setNameFn(getResult(), specialName.str());
4880 if (type.isGround()) {
4881 if (!isa<IntegerAttr>(attr)) {
4882 op->emitOpError(
"Ground type is not an integer attribute");
4887 auto attrlist = dyn_cast<ArrayAttr>(attr);
4889 op->emitOpError(
"expected array attribute for aggregate constant");
4892 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4893 if (array.getNumElements() != attrlist.size()) {
4894 op->emitOpError(
"array attribute (")
4895 << attrlist.size() <<
") has wrong size for vector constant ("
4896 << array.getNumElements() <<
")";
4899 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4903 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4904 if (bundle.getNumElements() != attrlist.size()) {
4905 op->emitOpError(
"array attribute (")
4906 << attrlist.size() <<
") has wrong size for bundle constant ("
4907 << bundle.getNumElements() <<
")";
4910 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4911 if (bundle.getElement(i).isFlip) {
4912 op->emitOpError(
"Cannot have constant bundle type with flip");
4920 op->emitOpError(
"Unknown aggregate type");
4924LogicalResult AggregateConstantOp::verify() {
4930Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4932 Attribute value = getFields();
4933 while (fieldID != 0) {
4934 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4935 auto index = bundle.getIndexForFieldID(fieldID);
4936 fieldID -= bundle.getFieldID(index);
4937 type = bundle.getElementType(index);
4938 value = cast<ArrayAttr>(value)[index];
4940 auto vector = type_cast<FVectorType>(type);
4941 auto index = vector.getIndexForFieldID(fieldID);
4942 fieldID -= vector.getFieldID(index);
4943 type = vector.getElementType();
4944 value = cast<ArrayAttr>(value)[index];
4950LogicalResult FIntegerConstantOp::verify() {
4951 auto i = getValueAttr();
4952 if (!i.getType().isSignedInteger())
4953 return emitOpError(
"value must be signed");
4957void FIntegerConstantOp::print(OpAsmPrinter &p) {
4959 p.printAttributeWithoutType(getValueAttr());
4960 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4963ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4964 OperationState &result) {
4965 auto *
context = parser.getContext();
4966 auto &properties = result.getOrAddProperties<Properties>();
4968 if (parser.parseInteger(value) ||
4969 parser.parseOptionalAttrDict(result.attributes))
4971 result.addTypes(FIntegerType::get(
context));
4973 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4974 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4975 properties.setValue(valueAttr);
4979ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4980 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4983 if (parser.parseOperandList(operands) ||
4984 parser.parseOptionalAttrDict(result.attributes) ||
4985 parser.parseColonType(type))
4987 result.addTypes(type);
4989 return parser.resolveOperands(operands, type.getElementType(),
4993void ListCreateOp::print(OpAsmPrinter &p) {
4995 p.printOperands(getElements());
4996 p.printOptionalAttrDict((*this)->getAttrs());
4997 p <<
" : " << getType();
5000LogicalResult ListCreateOp::verify() {
5001 if (getElements().
empty())
5004 auto elementType = getElements().front().getType();
5005 auto listElementType = getType().getElementType();
5007 return emitOpError(
"has elements of type ")
5008 <<
elementType <<
" instead of " << listElementType;
5013LogicalResult BundleCreateOp::verify() {
5014 BundleType resultType = getType();
5015 if (resultType.getNumElements() != getFields().size())
5016 return emitOpError(
"number of fields doesn't match type");
5017 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5019 resultType.getElementTypePreservingConst(i),
5020 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5021 return emitOpError(
"type of element doesn't match bundle for field ")
5022 << resultType.getElement(i).name;
5027LogicalResult VectorCreateOp::verify() {
5028 FVectorType resultType = getType();
5029 if (resultType.getNumElements() != getFields().size())
5030 return emitOpError(
"number of fields doesn't match type");
5031 auto elemTy = resultType.getElementTypePreservingConst();
5032 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5034 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5035 return emitOpError(
"type of element doesn't match vector element");
5041UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5043 auto classType = dyn_cast<ClassType>(getType());
5047 auto className = classType.getNameAttr();
5049 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5051 return emitOpError() <<
"refers to non-existent class ("
5052 << className.getAttr() <<
")";
5055 if (!isa<ClassLike>(op))
5056 return emitOpError() <<
"refers to a non-class type ("
5057 << className.getAttr() <<
")";
5066LogicalResult FEnumCreateOp::verify() {
5067 FEnumType resultType = getResult().getType();
5068 auto elementIndex = resultType.getElementIndex(
getFieldName());
5070 return emitOpError(
"label ")
5071 <<
getFieldName() <<
" is not a member of the enumeration type "
5074 resultType.getElementTypePreservingConst(*elementIndex),
5075 getInput().getType()))
5076 return emitOpError(
"type of element doesn't match enum element");
5080void FEnumCreateOp::print(OpAsmPrinter &printer) {
5083 printer <<
'(' << getInput() <<
')';
5084 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5085 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5087 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5088 ArrayRef<Type>{getResult().getType()});
5091ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5092 auto *
context = parser.getContext();
5093 auto &properties = result.getOrAddProperties<Properties>();
5095 OpAsmParser::UnresolvedOperand input;
5096 std::string fieldName;
5097 mlir::FunctionType functionType;
5098 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5099 parser.parseOperand(input) || parser.parseRParen() ||
5100 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5101 parser.parseType(functionType))
5104 if (functionType.getNumInputs() != 1)
5105 return parser.emitError(parser.getNameLoc(),
"single input type required");
5106 if (functionType.getNumResults() != 1)
5107 return parser.emitError(parser.getNameLoc(),
"single result type required");
5109 auto inputType = functionType.getInput(0);
5110 if (parser.resolveOperand(input, inputType, result.operands))
5113 auto outputType = functionType.getResult(0);
5114 auto enumType = type_dyn_cast<FEnumType>(outputType);
5116 return parser.emitError(parser.getNameLoc(),
5117 "output must be enum type, got ")
5119 auto fieldIndex = enumType.getElementIndex(fieldName);
5121 return parser.emitError(parser.getNameLoc(),
5122 "unknown field " + fieldName +
" in enum type ")
5125 properties.setFieldIndex(
5126 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5128 result.addTypes(enumType);
5137LogicalResult IsTagOp::verify() {
5138 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5139 return emitOpError(
"element index is greater than the number of fields in "
5144void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5145 printer <<
' ' << getInput() <<
' ';
5147 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5148 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5149 printer <<
" : " << getInput().getType();
5152ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5153 auto *
context = parser.getContext();
5154 auto &properties = result.getOrAddProperties<Properties>();
5156 OpAsmParser::UnresolvedOperand input;
5157 std::string fieldName;
5159 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5160 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5161 parser.parseType(inputType))
5164 if (parser.resolveOperand(input, inputType, result.operands))
5167 auto enumType = type_dyn_cast<FEnumType>(inputType);
5169 return parser.emitError(parser.getNameLoc(),
5170 "input must be enum type, got ")
5172 auto fieldIndex = enumType.getElementIndex(fieldName);
5174 return parser.emitError(parser.getNameLoc(),
5175 "unknown field " + fieldName +
" in enum type ")
5178 properties.setFieldIndex(
5179 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5181 result.addTypes(UIntType::get(
context, 1,
false));
5186FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5187 PropertyRef properties,
5188 mlir::RegionRange regions,
5189 std::optional<Location> loc) {
5190 Adaptor adaptor(operands, attrs, properties, regions);
5191 return UIntType::get(attrs.getContext(), 1,
5192 isConst(adaptor.getInput().getType()));
5195template <
typename OpTy>
5197 auto *
context = parser.getContext();
5199 OpAsmParser::UnresolvedOperand input;
5200 std::string fieldName;
5202 if (parser.parseOperand(input) || parser.parseLSquare() ||
5203 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5204 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5205 parser.parseType(inputType))
5208 if (parser.resolveOperand(input, inputType, result.operands))
5211 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5213 return parser.emitError(parser.getNameLoc(),
5214 "input must be bundle type, got ")
5216 auto fieldIndex = bundleType.getElementIndex(fieldName);
5218 return parser.emitError(parser.getNameLoc(),
5219 "unknown field " + fieldName +
" in bundle type ")
5222 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5223 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5225 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5228 result.addTypes(type);
5233ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5234 auto *
context = parser.getContext();
5236 OpAsmParser::UnresolvedOperand input;
5237 std::string fieldName;
5239 if (parser.parseOperand(input) || parser.parseLSquare() ||
5240 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5241 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5242 parser.parseType(inputType))
5245 if (parser.resolveOperand(input, inputType, result.operands))
5248 auto enumType = type_dyn_cast<FEnumType>(inputType);
5250 return parser.emitError(parser.getNameLoc(),
5251 "input must be enum type, got ")
5253 auto fieldIndex = enumType.getElementIndex(fieldName);
5255 return parser.emitError(parser.getNameLoc(),
5256 "unknown field " + fieldName +
" in enum type ")
5259 result.getOrAddProperties<Properties>().setFieldIndex(
5260 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5262 SmallVector<Type> inferredReturnTypes;
5263 if (failed(SubtagOp::inferReturnTypes(
5264 context, result.location, result.operands,
5265 result.attributes.getDictionary(
context), result.getRawProperties(),
5266 result.regions, inferredReturnTypes)))
5268 result.addTypes(inferredReturnTypes);
5273ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5274 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5276ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5277 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5280template <
typename OpTy>
5282 printer <<
' ' << op.getInput() <<
'[';
5283 printer.printKeywordOrString(op.getFieldName());
5285 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5286 elidedAttrs.push_back(
"fieldIndex");
5287 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5288 printer <<
" : " << op.getInput().getType();
5290void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5291 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5293void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5294 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5297void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5298 printer <<
' ' << getInput() <<
'[';
5301 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5302 elidedAttrs.push_back(
"fieldIndex");
5303 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5304 printer <<
" : " << getInput().getType();
5307template <
typename OpTy>
5309 if (op.getFieldIndex() >=
5310 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5312 return op.emitOpError(
"subfield element index is greater than the number "
5313 "of fields in the bundle type");
5316LogicalResult SubfieldOp::verify() {
5317 return verifySubfieldLike<SubfieldOp>(*
this);
5319LogicalResult OpenSubfieldOp::verify() {
5320 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5323LogicalResult SubtagOp::verify() {
5324 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5325 return emitOpError(
"subfield element index is greater than the number "
5326 "of fields in the bundle type");
5336 SmallVector<Operation *, 8> worklist({op});
5340 bool constant =
true;
5346 while (constant && !(worklist.empty()))
5347 TypeSwitch<Operation *>(worklist.pop_back_val())
5348 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5349 if (
auto definingOp = op.getInput().getDefiningOp())
5350 worklist.push_back(definingOp);
5353 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5354 for (
auto &use : op.getResult().getUses())
5355 worklist.push_back(use.getOwner());
5357 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5358 .Default([&](
auto) { constant =
false; });
5367 if (
auto *op = value.getDefiningOp())
5372LogicalResult ConstCastOp::verify() {
5374 return emitOpError() << getInput().getType()
5375 <<
" is not 'const'-castable to "
5376 << getResult().getType();
5380FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5381 std::optional<Location> loc) {
5382 auto inType = type_cast<BundleType>(type);
5384 if (fieldIndex >= inType.getNumElements())
5386 "subfield element index is greater than the "
5387 "number of fields in the bundle type");
5391 return inType.getElementTypePreservingConst(fieldIndex);
5394FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5395 std::optional<Location> loc) {
5396 auto inType = type_cast<OpenBundleType>(type);
5398 if (fieldIndex >= inType.getNumElements())
5400 "subfield element index is greater than the "
5401 "number of fields in the bundle type");
5405 return inType.getElementTypePreservingConst(fieldIndex);
5408bool SubfieldOp::isFieldFlipped() {
5409 BundleType bundle = getInput().getType();
5410 return bundle.getElement(getFieldIndex()).isFlip;
5412bool OpenSubfieldOp::isFieldFlipped() {
5413 auto bundle = getInput().getType();
5414 return bundle.getElement(getFieldIndex()).isFlip;
5417FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5418 std::optional<Location> loc) {
5419 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5420 if (fieldIndex < vectorType.getNumElements())
5421 return vectorType.getElementTypePreservingConst();
5423 "' in vector type ", type);
5428FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5429 std::optional<Location> loc) {
5430 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5431 if (fieldIndex < vectorType.getNumElements())
5432 return vectorType.getElementTypePreservingConst();
5434 "' in vector type ", type);
5440FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5441 PropertyRef properties,
5442 mlir::RegionRange regions,
5443 std::optional<Location> loc) {
5444 Adaptor adaptor(operands, attrs, properties, regions);
5445 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5446 auto fieldIndex = adaptor.getFieldIndex();
5448 if (fieldIndex >= inType.getNumElements())
5450 "subtag element index is greater than the "
5451 "number of fields in the enum type");
5455 auto elementType = inType.getElement(fieldIndex).type;
5459FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5460 std::optional<Location> loc) {
5461 if (!type_isa<UIntType>(indexType))
5465 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5467 return vectorType.getElementTypePreservingConst();
5468 return vectorType.getElementType().getAllConstDroppedType();
5476 std::optional<Location> loc) {
5477 auto inType = type_cast<FEnumType>(input);
5478 return UIntType::get(inType.getContext(), inType.getTagWidth());
5481ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5482 OpAsmParser::UnresolvedOperand index;
5483 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5484 Type indexType, elemType;
5486 if (parser.parseOperand(index) || parser.parseComma() ||
5487 parser.parseOperandList(inputs) ||
5488 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5489 parser.parseType(indexType) || parser.parseComma() ||
5490 parser.parseType(elemType))
5493 if (parser.resolveOperand(index, indexType, result.operands))
5496 result.addTypes(elemType);
5498 return parser.resolveOperands(inputs, elemType, result.operands);
5501void MultibitMuxOp::print(OpAsmPrinter &p) {
5502 p <<
" " << getIndex() <<
", ";
5503 p.printOperands(getInputs());
5504 p.printOptionalAttrDict((*this)->getAttrs());
5505 p <<
" : " << getIndex().getType() <<
", " << getType();
5508FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5509 DictionaryAttr attrs,
5510 PropertyRef properties,
5511 mlir::RegionRange regions,
5512 std::optional<Location> loc) {
5513 if (operands.size() < 2)
5517 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5518 return operands[1].getType() == op.getType();
5522 return type_cast<FIRRTLType>(operands[1].getType());
5529LogicalResult ObjectSubfieldOp::inferReturnTypes(
5530 MLIRContext *
context, std::optional<mlir::Location> location,
5531 ValueRange operands, DictionaryAttr attributes, PropertyRef properties,
5532 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5534 inferReturnType(operands, attributes, properties, regions, location);
5537 inferredReturnTypes.push_back(type);
5541Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5542 std::optional<Location> loc) {
5543 auto classType = dyn_cast<ClassType>(inType);
5547 if (classType.getNumElements() <= fieldIndex)
5549 "number of fields in the object");
5550 return classType.getElement(fieldIndex).type;
5553void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5554 auto input = getInput();
5555 auto classType = input.getType();
5556 p <<
' ' << input <<
"[";
5557 p.printKeywordOrString(classType.getElement(getIndex()).name);
5559 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5560 p <<
" : " << classType;
5563ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5564 OperationState &result) {
5565 auto *
context = parser.getContext();
5567 OpAsmParser::UnresolvedOperand input;
5568 std::string fieldName;
5569 ClassType inputType;
5570 if (parser.parseOperand(input) || parser.parseLSquare() ||
5571 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5572 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5573 parser.parseType(inputType) ||
5574 parser.resolveOperand(input, inputType, result.operands))
5577 auto index = inputType.getElementIndex(fieldName);
5579 return parser.emitError(parser.getNameLoc(),
5580 "unknown field " + fieldName +
" in class type ")
5582 result.getOrAddProperties<Properties>().setIndex(
5583 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5585 SmallVector<Type> inferredReturnTypes;
5586 if (failed(inferReturnTypes(
context, result.location, result.operands,
5587 result.attributes.getDictionary(
context),
5588 result.getRawProperties(), result.regions,
5589 inferredReturnTypes)))
5591 result.addTypes(inferredReturnTypes);
5608 int32_t &rhsWidth,
bool &isConstResult,
5609 std::optional<Location> loc) {
5611 auto lhsi = type_dyn_cast<IntType>(lhs);
5612 auto rhsi = type_dyn_cast<IntType>(rhs);
5613 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5616 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5618 else if (!lhsi && rhsi)
5619 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5621 else if (!lhsi && !rhsi)
5622 mlir::emitError(*loc,
"operands must be integer types, not ")
5623 << lhs <<
" and " << rhs;
5625 mlir::emitError(*loc,
"operand signedness must match");
5630 lhsWidth = lhsi.getWidthOrSentinel();
5631 rhsWidth = rhsi.getWidthOrSentinel();
5632 isConstResult = lhsi.isConst() && rhsi.isConst();
5637 assert(op->getNumOperands() == 2 &&
5638 "SameOperandsIntTypeKind on non-binary op");
5639 int32_t lhsWidth, rhsWidth;
5642 op->getOperand(1).getType(), lhsWidth,
5643 rhsWidth, isConstResult, op->getLoc()));
5647 std::optional<Location> loc) {
5648 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5649 bool isConstResult =
false;
5653 if (lhsWidth != -1 && rhsWidth != -1)
5654 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5655 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5660 std::optional<Location> loc) {
5661 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5662 bool isConstResult =
false;
5666 if (lhsWidth != -1 && rhsWidth != -1)
5667 resultWidth = lhsWidth + rhsWidth;
5669 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5674 std::optional<Location> loc) {
5675 int32_t lhsWidth, rhsWidth;
5676 bool isConstResult =
false;
5681 if (type_isa<UIntType>(lhs))
5682 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5685 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5686 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5690 std::optional<Location> loc) {
5691 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5692 bool isConstResult =
false;
5696 if (lhsWidth != -1 && rhsWidth != -1)
5697 resultWidth = std::min(lhsWidth, rhsWidth);
5698 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5703 std::optional<Location> loc) {
5704 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5705 bool isConstResult =
false;
5709 if (lhsWidth != -1 && rhsWidth != -1) {
5710 resultWidth = std::max(lhsWidth, rhsWidth);
5711 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5714 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5718 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5722 std::optional<Location> loc) {
5723 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5726 auto lhsVec = type_cast<FVectorType>(lhs);
5727 auto rhsVec = type_cast<FVectorType>(rhs);
5729 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5734 rhsVec.getElementTypePreservingConst(), loc);
5737 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5738 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5739 lhsVec.isConst() && rhsVec.isConst() &&
5740 elemBaseType.isConst());
5744 std::optional<Location> loc) {
5745 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5748FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5749 PropertyRef properties,
5750 mlir::RegionRange regions,
5751 std::optional<Location> loc) {
5753 if (operands.empty())
5754 return UIntType::get(attrs.getContext(), 0);
5757 bool isSigned = type_isa<SIntType>(operands[0].getType());
5758 for (
auto operand : operands) {
5759 auto type = type_dyn_cast<IntType>(operand.getType());
5762 if (type.isSigned() != isSigned)
5764 "all operands must have same signedness");
5768 int32_t resultWidth = 0;
5769 bool isConstResult =
true;
5771 for (
auto operand : operands) {
5772 auto type = type_cast<IntType>(operand.getType());
5773 int32_t width = type.getWidthOrSentinel();
5780 if (resultWidth != -1)
5781 resultWidth += width;
5784 isConstResult &= type.isConst();
5788 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5792 std::optional<Location> loc) {
5793 auto lhsi = type_dyn_cast<IntType>(lhs);
5794 auto rhsui = type_dyn_cast<UIntType>(rhs);
5795 if (!rhsui || !lhsi)
5797 loc,
"first operand should be integer, second unsigned int");
5801 auto width = lhsi.getWidthOrSentinel();
5802 if (width == -1 || !rhsui.getWidth().has_value()) {
5805 auto amount = *rhsui.getWidth();
5808 "shift amount too large: second operand of "
5809 "dshl is wider than 31 bits");
5810 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5811 if (newWidth > INT32_MAX)
5813 loc,
"shift amount too large: first operand shifted by maximum "
5814 "amount exceeds maximum width");
5817 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5818 lhsi.
isConst() && rhsui.isConst());
5822 std::optional<Location> loc) {
5823 auto lhsi = type_dyn_cast<IntType>(lhs);
5824 auto rhsu = type_dyn_cast<UIntType>(rhs);
5827 loc,
"first operand should be integer, second unsigned int");
5828 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5832 std::optional<Location> loc) {
5833 auto lhsi = type_dyn_cast<IntType>(lhs);
5834 auto rhsu = type_dyn_cast<UIntType>(rhs);
5837 loc,
"first operand should be integer, second unsigned int");
5838 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5846 std::optional<Location> loc) {
5847 return UIntType::get(input.getContext(), 32);
5851 std::optional<Location> loc) {
5852 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5855 int32_t width = base.getBitWidthOrSentinel();
5858 return SIntType::get(input.getContext(), width, base.
isConst());
5862 std::optional<Location> loc) {
5863 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5866 int32_t width = base.getBitWidthOrSentinel();
5869 return UIntType::get(input.getContext(), width, base.
isConst());
5873 std::optional<Location> loc) {
5874 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5877 "operand must be single bit scalar base type");
5878 int32_t width = base.getBitWidthOrSentinel();
5879 if (width == -2 || width == 0 || width > 1)
5881 return AsyncResetType::get(input.getContext(), base.
isConst());
5885 std::optional<Location> loc) {
5886 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5889 return ResetType::get(input.getContext(), base.
isConst());
5893 std::optional<Location> loc) {
5894 return ClockType::get(input.getContext(),
isConst(input));
5898 std::optional<Location> loc) {
5899 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5900 auto width = uiType.getWidthOrSentinel();
5903 return SIntType::get(input.getContext(), width, uiType.
isConst());
5906 if (type_isa<SIntType>(input))
5913 std::optional<Location> loc) {
5914 auto inputi = type_dyn_cast<IntType>(input);
5917 int32_t width = inputi.getWidthOrSentinel();
5920 return SIntType::get(input.getContext(), width, inputi.
isConst());
5924 std::optional<Location> loc) {
5925 auto inputi = type_dyn_cast<IntType>(input);
5928 if (isa<UIntType>(inputi))
5930 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5935 std::optional<Location> loc) {
5936 return UIntType::get(input.getContext(), 1,
isConst(input));
5945 std::optional<Location> loc) {
5946 auto inputi = type_dyn_cast<IntType>(input);
5949 loc,
"input type should be the int type but got ", input);
5954 loc,
"high must be equal or greater than low, but got high = ", high,
5962 int32_t width = inputi.getWidthOrSentinel();
5963 if (width != -1 && high >= width)
5966 "high must be smaller than the width of input, but got high = ", high,
5967 ", width = ", width);
5969 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5973 std::optional<Location> loc) {
5975 auto inputi = type_dyn_cast<IntType>(input);
5976 if (amount < 0 || !inputi)
5978 loc,
"operand must have integer type and amount must be >= 0");
5980 int32_t width = inputi.getWidthOrSentinel();
5981 if (width != -1 && amount > width)
5984 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5999 bool isConstCondition,
6000 std::optional<Location> loc) {
6006 if (high.getTypeID() != low.getTypeID())
6007 return emitInferRetTypeError<FIRRTLBaseType>(
6008 loc,
"incompatible mux operand types, true value type: ", high,
6009 ", false value type: ", low);
6011 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
6016 if (type_isa<IntType>(low)) {
6021 if (highWidth == -1)
6023 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
6028 auto highEnum = type_dyn_cast<FEnumType>(high);
6029 auto lowEnum = type_dyn_cast<FEnumType>(low);
6030 if (lowEnum && highEnum) {
6031 if (lowEnum.getNumElements() != highEnum.getNumElements())
6032 return emitInferRetTypeError<FIRRTLBaseType>(
6033 loc,
"incompatible mux operand types, true value type: ", high,
6034 ", false value type: ", low);
6035 SmallVector<FEnumType::EnumElement> elements;
6036 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6038 if (high.name != low.name || high.value != low.value)
6039 return emitInferRetTypeError<FIRRTLBaseType>(
6040 loc,
"incompatible mux operand types, true value type: ", highEnum,
6041 ", false value type: ", lowEnum);
6048 elements.emplace_back(high.name, high.value, inner);
6050 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6054 auto highVector = type_dyn_cast<FVectorType>(high);
6055 auto lowVector = type_dyn_cast<FVectorType>(low);
6056 if (highVector && lowVector &&
6057 highVector.getNumElements() == lowVector.getNumElements()) {
6059 lowVector.getElementTypePreservingConst(),
6060 isConstCondition, loc);
6063 return FVectorType::get(inner, lowVector.getNumElements(),
6068 auto highBundle = type_dyn_cast<BundleType>(high);
6069 auto lowBundle = type_dyn_cast<BundleType>(low);
6070 if (highBundle && lowBundle) {
6071 auto highElements = highBundle.getElements();
6072 auto lowElements = lowBundle.getElements();
6075 SmallVector<BundleType::BundleElement> newElements;
6077 bool failed =
false;
6079 if (highElements[i].name != lowElements[i].name ||
6080 highElements[i].isFlip != lowElements[i].isFlip) {
6084 auto element = highElements[i];
6086 highBundle.getElementTypePreservingConst(i),
6087 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6090 newElements.push_back(element);
6093 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6095 return emitInferRetTypeError<FIRRTLBaseType>(
6096 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6097 ", false value type: ", low);
6102 return emitInferRetTypeError<FIRRTLBaseType>(
6103 loc,
"invalid mux operand types, true value type: ", high,
6104 ", false value type: ", low);
6109 std::optional<Location> loc) {
6110 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6111 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6112 if (!highType || !lowType)
6117FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6118 DictionaryAttr attrs,
6119 PropertyRef properties,
6120 mlir::RegionRange regions,
6121 std::optional<Location> loc) {
6122 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6123 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6124 if (!highType || !lowType)
6130FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6131 DictionaryAttr attrs,
6132 PropertyRef properties,
6133 mlir::RegionRange regions,
6134 std::optional<Location> loc) {
6135 SmallVector<FIRRTLBaseType> types;
6137 for (
unsigned i = 1; i < 5; i++) {
6138 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6143 isConst(operands[0].getType()), loc);
6147 result = types.back();
6154 std::optional<Location> loc) {
6155 auto inputi = type_dyn_cast<IntType>(input);
6156 if (amount < 0 || !inputi)
6158 loc,
"pad input must be integer and amount must be >= 0");
6160 int32_t width = inputi.getWidthOrSentinel();
6164 width = std::max<int32_t>(width, amount);
6165 return IntType::get(input.getContext(), inputi.isSigned(), width,
6170 std::optional<Location> loc) {
6171 auto inputi = type_dyn_cast<IntType>(input);
6172 if (amount < 0 || !inputi)
6174 loc,
"shl input must be integer and amount must be >= 0");
6176 int32_t width = inputi.getWidthOrSentinel();
6180 return IntType::get(input.getContext(), inputi.isSigned(), width,
6185 std::optional<Location> loc) {
6186 auto inputi = type_dyn_cast<IntType>(input);
6187 if (amount < 0 || !inputi)
6189 loc,
"shr input must be integer and amount must be >= 0");
6191 int32_t width = inputi.getWidthOrSentinel();
6194 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6195 width = std::max<int32_t>(minWidth, width - amount);
6198 return IntType::get(input.getContext(), inputi.isSigned(), width,
6203 std::optional<Location> loc) {
6205 auto inputi = type_dyn_cast<IntType>(input);
6206 if (amount < 0 || !inputi)
6208 loc,
"tail input must be integer and amount must be >= 0");
6210 int32_t width = inputi.getWidthOrSentinel();
6214 loc,
"amount must be less than or equal operand width");
6225void VerbatimExprOp::getAsmResultNames(
6226 function_ref<
void(Value, StringRef)> setNameFn) {
6230 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6231 auto name = getText();
6233 if (name.starts_with(
"`"))
6234 name = name.drop_front();
6235 name = name.take_while(isOkCharacter);
6237 setNameFn(getResult(), name);
6244void VerbatimWireOp::getAsmResultNames(
6245 function_ref<
void(Value, StringRef)> setNameFn) {
6249 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6250 auto name = getText();
6252 if (name.starts_with(
"`"))
6253 name = name.drop_front();
6254 name = name.take_while(isOkCharacter);
6256 setNameFn(getResult(), name);
6267 op->emitError() <<
"unknown width is not allowed for DPI";
6268 return WalkResult::interrupt();
6270 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6272 return WalkResult::advance();
6274 <<
"integer types used by DPI functions must have a "
6275 "specific bit width; "
6276 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6277 "32(int), 64(longint) "
6278 "or greater than 64, but got "
6280 return WalkResult::interrupt();
6285LogicalResult DPICallIntrinsicOp::verify() {
6286 if (
auto inputNames = getInputNames()) {
6287 if (getInputs().size() != inputNames->size())
6288 return emitError() <<
"inputNames has " << inputNames->size()
6289 <<
" elements but there are " << getInputs().size()
6290 <<
" input arguments";
6292 if (
auto outputName = getOutputName())
6293 if (getNumResults() == 0)
6294 return emitError() <<
"output name is given but there is no result";
6296 auto checkType = [
this](Type type) {
6299 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6300 llvm::all_of(this->getOperandTypes(), checkType));
6303SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6304DPICallIntrinsicOp::computeDataFlow() {
6308 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6310 for (
auto operand : getOperands()) {
6311 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6313 SmallVector<circt::FieldRef> operandFields;
6316 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6320 for (
auto result : getResults())
6323 for (
auto field : operandFields)
6324 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6334LogicalResult HWStructCastOp::verify() {
6336 BundleType bundleType;
6337 hw::StructType structType;
6338 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6339 structType = dyn_cast<hw::StructType>(getType());
6341 return emitError(
"result type must be a struct");
6342 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6343 structType = dyn_cast<hw::StructType>(getOperand().getType());
6345 return emitError(
"operand type must be a struct");
6347 return emitError(
"either source or result type must be a bundle type");
6350 auto firFields = bundleType.getElements();
6351 auto hwFields = structType.getElements();
6352 if (firFields.size() != hwFields.size())
6353 return emitError(
"bundle and struct have different number of fields");
6355 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6356 if (firFields[findex].name.getValue() != hwFields[findex].name)
6357 return emitError(
"field names don't match '")
6358 << firFields[findex].name.getValue() <<
"', '"
6359 << hwFields[findex].name.getValue() <<
"'";
6363 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6364 return emitError(
"size of field '")
6365 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6372LogicalResult BitCastOp::verify() {
6373 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6375 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6377 if (*inTypeBits == *resTypeBits) {
6380 return emitError(
"cannot cast non-'const' input type ")
6381 << getOperand().getType() <<
" to 'const' result type "
6385 return emitError(
"the bitwidth of input (")
6386 << *inTypeBits <<
") and result (" << *resTypeBits
6389 if (!inTypeBits.has_value())
6390 return emitError(
"bitwidth cannot be determined for input operand type ")
6391 << getInput().getType();
6392 return emitError(
"bitwidth cannot be determined for result type ")
6403 NamedAttrList &resultAttrs) {
6404 auto result = parser.parseOptionalAttrDict(resultAttrs);
6405 if (!resultAttrs.get(
"annotations"))
6406 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6412 DictionaryAttr attr,
6413 ArrayRef<StringRef> extraElides = {}) {
6414 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6416 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6417 elidedAttrs.push_back(
"annotations");
6419 elidedAttrs.push_back(
"nameKind");
6421 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6427 NamedAttrList &resultAttrs) {
6430 if (!resultAttrs.get(
"portAnnotations")) {
6431 SmallVector<Attribute, 16> portAnnotations(
6432 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6433 resultAttrs.append(
"portAnnotations",
6434 parser.getBuilder().getArrayAttr(portAnnotations));
6441 DictionaryAttr attr,
6442 ArrayRef<StringRef> extraElides = {}) {
6443 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6445 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6446 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6447 elidedAttrs.push_back(
"portAnnotations");
6456 firrtl::NameKindEnumAttr &result) {
6459 if (!parser.parseOptionalKeyword(&keyword,
6460 {
"interesting_name",
"droppable_name"})) {
6461 auto kind = symbolizeNameKindEnum(keyword);
6462 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6468 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6473 firrtl::NameKindEnumAttr attr,
6474 ArrayRef<StringRef> extraElides = {}) {
6475 if (attr.getValue() != NameKindEnum::DroppableName)
6476 p <<
" " << stringifyNameKindEnum(attr.getValue());
6484 NamedAttrList &resultAttrs) {
6492 DictionaryAttr attrs) {
6493 SmallVector<StringRef, 4> elides;
6495 elides.push_back(Forceable::getForceableAttrName());
6505 OpAsmParser &parser,
6506 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &fieldValues,
6507 SmallVectorImpl<Type> &fieldTypes, Type &resultType) {
6509 if (parser.parseType(resultType))
6512 auto domainType = dyn_cast<DomainType>(resultType);
6514 return parser.emitError(parser.getCurrentLocation(),
6515 "expected domain type");
6518 auto fields = domainType.getFields();
6521 if (fieldValues.size() != fields.size())
6522 return parser.emitError(parser.getCurrentLocation(),
6523 "number of field values (" +
6524 Twine(fieldValues.size()) +
6525 ") does not match domain field count (" +
6526 Twine(fields.size()) +
")");
6529 fieldTypes.reserve(fields.size());
6530 for (
auto field : fields)
6531 fieldTypes.push_back(cast<DomainFieldAttr>(field).getType());
6537 OperandRange fieldValues,
6538 TypeRange fieldTypes, Type resultType) {
6546static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6551static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6562 if (ClassType::parseInterface(parser, type))
6569 type.printInterface(p);
6577 NamedAttrList &resultAttrs) {
6578 auto result = p.parseOptionalAttrDict(resultAttrs);
6579 if (!resultAttrs.get(
"name"))
6580 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6586 DictionaryAttr attr,
6587 ArrayRef<StringRef> extraElides = {}) {
6588 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6589 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6590 elides.push_back(
"name");
6592 p.printOptionalAttrDict(op->getAttrs(), elides);
6596 NamedAttrList &resultAttrs) {
6601 DictionaryAttr attr) {
6606 NamedAttrList &resultAttrs) {
6611 DictionaryAttr attr) {
6613 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6621 DictionaryAttr attr) {
6630 DictionaryAttr attr) {
6639 OpAsmSetValueNameFn setNameFn) {
6642 if (op->getNumResults() == 1)
6643 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6644 setNameFn(op->getResult(0), nameAttr.getValue());
6647void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6651void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6655void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6659void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6662void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6665void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6668void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6671void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6674void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6677void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6680void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6683void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6686void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6689void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6692void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6695void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6698void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6701void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6704void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6707void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6710void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6713void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6716void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6719void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6722void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6725void BoolAndOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6728void BoolOrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6731void BoolXorOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6734void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6737void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6740void PlusArgsValueIntrinsicOp::getAsmResultNames(
6741 OpAsmSetValueNameFn setNameFn) {
6744void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6747void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6750void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6753void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6756void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6759void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6762void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6765void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6768void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6771void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6774void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6777void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6780void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6783void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6786void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6789void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6792void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6796void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6800void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6804void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6808void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6812void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6816void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6820void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6824void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6828void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6832void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6836void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6840void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6844void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6848void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6852void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6856void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6864void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6868void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6872void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6876void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6880void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6884FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6885 DictionaryAttr attrs,
6886 PropertyRef properties,
6887 mlir::RegionRange regions,
6888 std::optional<Location> loc) {
6889 Type inType = operands[0].getType();
6890 auto inRefType = type_dyn_cast<RefType>(inType);
6893 loc,
"ref.resolve operand must be ref type, not ", inType);
6894 return inRefType.getType();
6897FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6898 PropertyRef properties,
6899 mlir::RegionRange regions,
6900 std::optional<Location> loc) {
6901 Type inType = operands[0].getType();
6902 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6905 loc,
"ref.send operand must be base type, not ", inType);
6906 return RefType::get(inBaseType.getPassiveType());
6909FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6910 std::optional<Location> loc) {
6911 auto refType = type_dyn_cast<RefType>(type);
6914 auto inType = refType.getType();
6920 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6921 if (fieldIndex < vectorType.getNumElements())
6922 return RefType::get(
6923 vectorType.getElementType().getConstType(
6924 vectorType.isConst() || vectorType.getElementType().isConst()),
6925 refType.getForceable(), refType.getLayer());
6927 "' in RefType of vector type ", refType);
6929 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6930 if (fieldIndex >= bundleType.getNumElements()) {
6932 "subfield element index is greater than "
6933 "the number of fields in the bundle type");
6935 return RefType::get(
6936 bundleType.getElement(fieldIndex)
6938 bundleType.isConst() ||
6939 bundleType.getElement(fieldIndex).type.isConst()),
6940 refType.getForceable(), refType.getLayer());
6944 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6947LogicalResult RefCastOp::verify() {
6951 getOperation(), srcLayers, dstLayers,
6952 "cannot discard layer requirements of input reference",
6953 "discarding layer requirements");
6956LogicalResult RefResolveOp::verify() {
6960 getOperation(), srcLayers, dstLayers,
6961 "ambient layers are insufficient to resolve reference");
6965 auto targetRef = getTarget();
6966 if (targetRef.getModule() !=
6967 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6968 return emitOpError() <<
"has non-local target";
6970 auto target = ns.
lookup(targetRef);
6972 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6974 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6979 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6980 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6981 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6982 << fType <<
" instead of expected " << getType().getType();
6983 diag.attachNote(loc) <<
"target resolves here";
6988 if (target.isPort()) {
6989 auto mod = cast<FModuleLike>(target.getOp());
6990 return checkFinalType(mod.getPortType(target.getPort()),
6991 mod.getPortLocation(target.getPort()));
6993 hw::InnerSymbolOpInterface symOp =
6994 cast<hw::InnerSymbolOpInterface>(target.getOp());
6995 if (!symOp.getTargetResult())
6996 return emitOpError(
"has target that cannot be probed")
6997 .attachNote(symOp.getLoc())
6998 .append(
"target resolves here");
7000 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
7001 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
7002 return emitOpError(
"is not dominated by target")
7003 .attachNote(symOp.getLoc())
7004 .append(
"target here");
7005 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
7008LogicalResult RefForceOp::verify() {
7012 getOperation(), destLayers, ambientLayers,
7013 "has insufficient ambient layers to force its reference");
7016LogicalResult RefForceInitialOp::verify() {
7020 getOperation(), destLayers, ambientLayers,
7021 "has insufficient ambient layers to force its reference");
7024LogicalResult RefReleaseOp::verify() {
7028 getOperation(), destLayers, ambientLayers,
7029 "has insufficient ambient layers to release its reference");
7032LogicalResult RefReleaseInitialOp::verify() {
7036 getOperation(), destLayers, ambientLayers,
7037 "has insufficient ambient layers to release its reference");
7040LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7041 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7043 return emitOpError(
"has an invalid symbol reference");
7045 if (!isa<hw::HierPathOp>(target))
7046 return emitOpError(
"does not target a hierpath op");
7052LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7053 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7055 return emitOpError(
"has an invalid symbol reference");
7057 if (!isa<hw::HierPathOp>(target))
7058 return emitOpError(
"does not target a hierpath op");
7068LogicalResult LayerBlockOp::verify() {
7069 auto layerName = getLayerName();
7070 auto *parentOp = (*this)->getParentOp();
7073 while (isa<WhenOp, MatchOp>(parentOp))
7074 parentOp = parentOp->getParentOp();
7078 auto nestedReferences = layerName.getNestedReferences();
7079 if (nestedReferences.empty()) {
7080 if (!isa<FModuleOp>(parentOp)) {
7081 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7082 "not have a 'firrtl.module' op as a parent";
7083 return diag.attachNote(parentOp->getLoc())
7084 <<
"illegal parent op defined here";
7087 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7088 if (!parentLayerBlock) {
7089 auto diag = emitOpError()
7090 <<
"has a nested layer symbol, but does not have a '"
7091 << getOperationName() <<
"' op as a parent'";
7092 return diag.attachNote(parentOp->getLoc())
7093 <<
"illegal parent op defined here";
7095 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7096 if (parentLayerBlockName.getRootReference() !=
7097 layerName.getRootReference() ||
7098 parentLayerBlockName.getNestedReferences() !=
7099 layerName.getNestedReferences().drop_back()) {
7100 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7101 return diag.attachNote(parentLayerBlock->getLoc())
7102 <<
"illegal parent layer block defined here";
7108 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7109 [&](Operation *op) -> WalkResult {
7111 if (isa<LayerBlockOp>(op))
7112 return WalkResult::skip();
7116 for (
auto operand : op->getOperands()) {
7118 if (
auto *definingOp = operand.getDefiningOp())
7122 auto type = operand.getType();
7125 if (isa<PropertyType>(type)) {
7126 auto diag = emitOpError() <<
"captures a property operand";
7127 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7128 diag.attachNote(op->getLoc()) <<
"operand is used here";
7129 return WalkResult::interrupt();
7134 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7136 if (isa<RefDefineOp>(connect))
7137 return WalkResult::advance();
7144 bool passive =
true;
7146 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7147 passive = type.isPassive();
7156 return WalkResult::advance();
7159 return WalkResult::advance();
7163 <<
"connects to a destination which is defined outside its "
7164 "enclosing layer block";
7165 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7166 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7167 return WalkResult::interrupt();
7170 return WalkResult::advance();
7173 return failure(result.wasInterrupted());
7177LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7179 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7181 return emitOpError(
"invalid symbol reference");
7191void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7192 setNameFn(getResult(),
"time");
7195void HierarchicalModuleNameOp::getAsmResultNames(
7196 OpAsmSetValueNameFn setNameFn) {
7197 setNameFn(getResult(),
"hierarchicalmodulename");
7200ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7201 ::mlir::OperationState &result) {
7203 OpAsmParser::UnresolvedOperand clock, cond;
7204 if (parser.parseOperand(clock) || parser.parseComma() ||
7205 parser.parseOperand(cond) || parser.parseComma())
7209 [&parser](llvm::SMLoc &loc, StringAttr &result,
7210 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7212 loc = parser.getCurrentLocation();
7215 std::string resultStr;
7216 if (parser.parseString(&resultStr))
7218 result = parser.getBuilder().getStringAttr(resultStr);
7221 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7227 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7229 llvm::SMLoc outputFileLoc, formatStringLoc;
7233 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7234 outputFileSubstitutions) ||
7235 parser.parseComma() ||
7238 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7246 Type clockType, condType;
7247 SmallVector<Type> restTypes;
7249 if (parser.parseColon() || parser.parseType(clockType) ||
7250 parser.parseComma() || parser.parseType(condType))
7253 if (succeeded(parser.parseOptionalComma())) {
7254 if (parser.parseTypeList(restTypes))
7259 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7260 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7261 static_cast<int32_t
>(substitutions.size())};
7264 if (parser.resolveOperand(clock, clockType, result.operands) ||
7265 parser.resolveOperand(cond, condType, result.operands) ||
7266 parser.resolveOperands(
7267 outputFileSubstitutions,
7268 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7269 outputFileLoc, result.operands) ||
7270 parser.resolveOperands(
7272 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7273 formatStringLoc, result.operands))
7279void FPrintFOp::print(OpAsmPrinter &p) {
7280 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7281 p.printAttributeWithoutType(getOutputFileAttr());
7282 if (!getOutputFileSubstitutions().
empty()) {
7284 p.printOperands(getOutputFileSubstitutions());
7288 p.printAttributeWithoutType(getFormatStringAttr());
7289 if (!getSubstitutions().
empty()) {
7291 p.printOperands(getSubstitutions());
7295 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7296 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7297 for (
auto type : getOperands().drop_front(2).getTypes()) {
7308LogicalResult FFlushOp::verify() {
7309 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7310 return emitOpError(
"substitutions without output file are not allowed");
7319 auto ref = getInstanceAttr();
7320 auto target = ns.
lookup(ref);
7322 return emitError() <<
"target " << ref <<
" cannot be resolved";
7324 if (!target.isOpOnly())
7325 return emitError() <<
"target " << ref <<
" is not an operation";
7327 auto instance = dyn_cast<InstanceOp>(target.getOp());
7329 return emitError() <<
"target " << ref <<
" is not an instance";
7331 if (!instance.getDoNotPrint())
7332 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7341void DomainCreateAnonOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7346DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7347 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7348 auto domainAttr = getDomainAttr();
7350 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7352 return emitOpError() <<
"references undefined symbol '" << domainAttr
7355 if (!isa<DomainOp>(symbol))
7356 return emitOpError() <<
"references symbol '" << domainAttr
7357 <<
"' which is not a domain";
7360 auto domainType = getResult().getType();
7361 return domainType.verifySymbolUses(getOperation(), symbolTable);
7364void DomainCreateOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7369DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7370 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7371 auto domainAttr = getDomainAttr();
7373 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7375 return emitOpError() <<
"references undefined symbol '" << domainAttr
7378 if (!isa<DomainOp>(symbol))
7379 return emitOpError() <<
"references symbol '" << domainAttr
7380 <<
"' which is not a domain";
7383 auto domainType = getResult().getType();
7384 return domainType.verifySymbolUses(getOperation(), symbolTable);
7387LogicalResult DomainCreateOp::verify() {
7389 auto domainType = getResult().getType();
7390 auto fields = domainType.getFields();
7391 auto fieldValues = getFieldValues();
7394 if (fieldValues.size() != fields.size())
7395 return emitOpError() <<
"has " << fieldValues.size()
7396 <<
" field value(s) but domain '"
7397 << domainType.getName() <<
"' expects "
7398 << fields.size() <<
" field(s)";
7401 for (
size_t i = 0; i < fields.size(); ++i) {
7402 auto fieldAttr = cast<DomainFieldAttr>(fields[i]);
7403 auto expectedType = fieldAttr.getType();
7404 auto actualType = fieldValues[i].getType();
7406 if (expectedType == actualType)
7409 return emitOpError() <<
"field value " << i <<
" has type " << actualType
7410 <<
" but domain field '" << fieldAttr.getName()
7411 <<
"' expects type " << expectedType;
7421StringAttr DomainSubfieldOp::getFieldName() {
7422 auto domainType = getInput().getType();
7423 auto fields = domainType.getFields();
7424 auto index = getFieldIndex();
7426 if (index >= fields.size())
7429 return cast<DomainFieldAttr>(fields[index]).getName();
7432Type DomainSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
7433 std::optional<Location> loc) {
7434 auto domainType = dyn_cast<DomainType>(inType);
7438 auto fields = domainType.getFields();
7439 if (fieldIndex >= fields.size())
7441 loc,
"field index ", fieldIndex,
7442 +
" is greater than the number of fields in the domain");
7444 return cast<DomainFieldAttr>(fields[fieldIndex]).getType();
7447Type DomainSubfieldOp::inferReturnType(ValueRange operands,
7448 mlir::DictionaryAttr attrs,
7449 mlir::PropertyRef properties,
7450 mlir::RegionRange regions,
7451 std::optional<Location> loc) {
7452 Adaptor adaptor(operands, attrs, properties, regions);
7453 return inferReturnType(adaptor.getInput().getType(), adaptor.getFieldIndex(),
7457DomainSubfieldOp DomainSubfieldOp::create(OpBuilder &builder, Type resultType,
7458 Value base,
unsigned fieldIndex) {
7459 OperationState state(builder.getUnknownLoc(),
7460 DomainSubfieldOp::getOperationName());
7461 state.addOperands(base);
7462 state.addAttribute(
"fieldIndex", builder.getI32IntegerAttr(fieldIndex));
7463 state.addTypes(resultType);
7464 return cast<DomainSubfieldOp>(builder.create(state));
7467LogicalResult DomainSubfieldOp::inferReturnTypes(
7468 MLIRContext *
context, std::optional<Location> location, ValueRange operands,
7469 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
7470 SmallVectorImpl<Type> &inferredReturnTypes) {
7471 Adaptor adaptor(operands, attributes, properties, regions);
7472 auto resultType = inferReturnType(adaptor.getInput().getType(),
7473 adaptor.getFieldIndex(), location);
7476 inferredReturnTypes.push_back(resultType);
7480void DomainSubfieldOp::print(OpAsmPrinter &p) {
7481 p <<
' ' << getInput() <<
"[";
7484 p.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
7485 p <<
" : " << getInput().getType();
7488ParseResult DomainSubfieldOp::parse(OpAsmParser &parser,
7489 OperationState &result) {
7490 auto *
context = parser.getContext();
7492 OpAsmParser::UnresolvedOperand input;
7493 std::string fieldName;
7494 DomainType inputType;
7496 if (parser.parseOperand(input) || parser.parseLSquare() ||
7497 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
7498 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
7499 parser.parseType(inputType) ||
7500 parser.resolveOperand(input, inputType, result.operands))
7504 auto fieldIndex = inputType.getFieldIndex(fieldName);
7506 return parser.emitError(parser.getNameLoc(),
7507 "unknown field '" + fieldName +
"' in domain type");
7510 result.addAttribute(
7512 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
7515 auto resultType = inferReturnType(inputType, *fieldIndex, std::nullopt);
7519 result.addTypes(resultType);
7528#define GET_OP_CLASSES
7529#include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
static void printNameKind(OpAsmPrinter &p, Operation *op, firrtl::NameKindEnumAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static std::unique_ptr< Context > context
static Attribute fixDomainInfoInsertions(MLIRContext *context, Attribute domainInfoAttr, ArrayRef< unsigned > indexMap)
Return an updated domain info Attribute with domain indices updated based on port insertions.
static LogicalResult verifyProbeType(RefType refType, Location loc, CircuitOp circuitOp, SymbolTableCollection &symbolTable, Twine start)
static ArrayAttr fixDomainInfoDeletions(MLIRContext *context, ArrayAttr domainInfoAttr, const llvm::BitVector &portIndices, bool supportsEmptyAttr)
static SmallVector< PortInfo > getPortImpl(FModuleLike module)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static FlatSymbolRefAttr getDomainTypeName(Value value)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static 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 printFieldsFromDomain(OpAsmPrinter &p, Operation *op, OperandRange fieldValues, TypeRange fieldTypes, Type resultType)
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void 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.