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() {
3811LogicalResult RegResetOp::verify() {
3812 auto reset = getResetValue();
3819 return emitError(
"type mismatch between register ")
3820 << regType <<
" and reset value " << resetType;
3825std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3827void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3836FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3837 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3839 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3841 if (!isa<FModuleLike>(op)) {
3842 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3843 <<
" is not a module";
3844 d.attachNote(op->getLoc()) <<
"target defined here";
3856SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3857 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3859 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3861 auto complain = [&] {
3862 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3863 d.attachNote(op->getLoc()) <<
"target defined here";
3867 auto module = dyn_cast<FModuleLike>(op);
3869 return complain() <<
"is not a module";
3871 auto numPorts =
module.getNumPorts();
3873 return complain() <<
"must have at least 4 ports, got " << numPorts
3877 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3878 llvm::function_ref<bool(Type)> checkType,
3879 StringRef expType) {
3880 auto name =
module.getPortNameAttr(idx);
3881 if (name != expName) {
3882 complain() <<
"port " << idx <<
" must be called \"" << expName
3883 <<
"\", got " << name <<
" instead";
3886 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3890 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3891 <<
", got " << stringify(dir) <<
" instead";
3894 if (
auto type = module.getPortType(idx); !checkType(type)) {
3895 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3896 <<
"', got " << type <<
" instead";
3902 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3903 auto isBool = [](Type type) {
3904 if (
auto uintType = dyn_cast<UIntType>(type))
3905 return uintType.getWidth() == 1;
3909 if (!checkPort(0,
"clock",
Direction::In, isClock,
"clock") ||
3916 for (
unsigned i = 4; i < numPorts; ++i) {
3917 auto type =
module.getPortType(i);
3918 if (!isa<PropertyType>(type))
3919 return complain() <<
"port " << i <<
" may only be a property type, got "
3920 << type <<
" instead";
3930void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3934SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3935RegResetOp::computeDataFlow() {
3940std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3942LogicalResult WireOp::verify() {
3944 if (type_isa<DomainType>(getResult().getType()) && !getDomains().
empty())
3945 return emitOpError(
"of domain type must not have domain associations");
3948 auto domains = getDomains();
3949 if (!domains.size())
3962 using oldValueAndDiag = std::pair<Value, std::unique_ptr<InFlightDiagnostic>>;
3964 bool hasErrors =
false;
3965 for (
auto domain : domains) {
3966 auto domainType = cast<DomainType>(domain.getType());
3967 auto domainName = domainType.getName();
3970 auto [it, inserted] =
3971 domainInfo.try_emplace(domainName, std::make_pair(domain,
nullptr));
3978 auto &[value, diag] = it->second;
3984 diag = std::make_unique<InFlightDiagnostic>(
3985 emitOpError() <<
"associated with multiple operands of '"
3986 << domainName.getValue() <<
"' kind");
3987 diag->attachNote(value.getLoc()) <<
"first domain operand here";
3992 diag->attachNote(domain.getLoc())
3993 <<
"additional colliding domain operand here";
4005 for (
auto &[_, diag] : domainInfo.values())
4011LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4012 if (
auto refType = type_dyn_cast<RefType>(getType(0)))
4014 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
4015 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
4017 if (
auto domainType = type_dyn_cast<DomainType>(getType(0)))
4018 return domainType.verifySymbolUses(getOperation(), symbolTable);
4027LogicalResult ContractOp::verify() {
4028 if (getBody().getArgumentTypes() != getInputs().getType())
4029 return emitOpError(
"result types and region argument types must match");
4038OptionCaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4039 auto caseMacro = getCaseMacroAttr();
4044 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4045 auto *refOp = symbolTable.lookupSymbolIn(circuitOp, caseMacro);
4047 return emitOpError(
"case_macro references an undefined symbol: ")
4050 if (!isa<sv::MacroDeclOp>(refOp))
4051 return emitOpError(
"case_macro must reference a macro declaration");
4060void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
4062 build(builder, state, klass.getInstanceType(),
4063 StringAttr::get(builder.getContext(), name));
4066LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
4067 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
4068 auto classType = getType();
4069 auto className = classType.getNameAttr();
4072 auto classOp = dyn_cast_or_null<ClassLike>(
4073 symbolTable.lookupSymbolIn(circuitOp, className));
4075 return emitOpError() <<
"references unknown class " << className;
4078 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
4084StringAttr ObjectOp::getClassNameAttr() {
4085 return getType().getNameAttr().getAttr();
4088StringRef ObjectOp::getClassName() {
return getType().getName(); }
4090ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
4091 auto symRef = getType().getNameAttr();
4092 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
4095Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
4096 return getReferencedClass(symtbl);
4099StringRef ObjectOp::getInstanceName() {
return getName(); }
4101StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
4103StringAttr ObjectOp::getReferencedModuleNameAttr() {
4104 return getClassNameAttr();
4107void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4108 setNameFn(getResult(),
getName());
4115LogicalResult AttachOp::verify() {
4117 std::optional<int32_t> commonWidth;
4118 for (
auto operand : getOperands()) {
4119 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
4123 commonWidth = thisWidth;
4126 if (commonWidth != thisWidth)
4127 return emitOpError(
"is inavlid as not all known operand widths match");
4134 Value dst = connect->getOperand(0);
4135 Value src = connect->getOperand(1);
4144 if (isa<PropertyType>(src.getType()) ||
4148 auto diag = emitError(connect->getLoc());
4149 diag <<
"connect has invalid flow: the source expression ";
4151 diag <<
"\"" << srcName <<
"\" ";
4152 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
4153 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
4161 auto diag = emitError(connect->getLoc());
4162 diag <<
"connect has invalid flow: the destination expression ";
4164 diag <<
"\"" << dstName <<
"\" ";
4165 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
4166 return diag.attachNote(dstRef.getLoc())
4167 <<
"the destination was defined here";
4176 bool outerTypeIsConst =
false) {
4177 auto typeIsConst = outerTypeIsConst || type.
isConst();
4182 if (
auto bundleType = type_dyn_cast<BundleType>(type))
4183 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
4184 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
4188 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
4200 auto dest = connect.getDest();
4201 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
4202 auto src = connect.getSrc();
4203 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
4204 if (!destType || !srcType)
4207 auto destRefinedType = destType;
4208 auto srcRefinedType = srcType;
4213 auto findFieldDeclarationRefiningFieldType =
4215 while (
auto *definingOp = value.getDefiningOp()) {
4216 bool shouldContinue =
true;
4217 TypeSwitch<Operation *>(definingOp)
4218 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4219 .Case<SubaccessOp>([&](SubaccessOp op) {
4223 .getElementTypePreservingConst()
4225 originalFieldType = originalFieldType.getConstType(
true);
4226 value = op.getInput();
4228 .Default([&](Operation *) { shouldContinue =
false; });
4229 if (!shouldContinue)
4235 auto destDeclaration =
4236 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4237 auto srcDeclaration =
4238 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4240 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4241 Value declaration) -> LogicalResult {
4242 auto *declarationBlock = declaration.getParentBlock();
4243 auto *block = connect->getBlock();
4244 while (block && block != declarationBlock) {
4245 auto *parentOp = block->getParentOp();
4247 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4248 whenOp && !whenOp.getCondition().getType().isConst()) {
4250 return connect.emitOpError()
4251 <<
"assignment to 'const' type " << type
4252 <<
" is dependent on a non-'const' condition";
4253 return connect->emitOpError()
4254 <<
"assignment to nested 'const' member of type " << type
4255 <<
" is dependent on a non-'const' condition";
4258 block = parentOp->getBlock();
4263 auto emitSubaccessError = [&] {
4264 return connect.emitError(
4265 "assignment to non-'const' subaccess of 'const' type is disallowed");
4271 if (destType != destRefinedType)
4272 return emitSubaccessError();
4274 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4279 if (srcRefinedType.containsConst() &&
4282 if (srcType != srcRefinedType)
4283 return emitSubaccessError();
4284 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4301 auto dest = connect.getDest();
4302 for (
auto *user : dest.getUsers()) {
4303 if (
auto c = dyn_cast<FConnectLike>(user);
4304 c && c.getDest() == dest && c != connect) {
4305 auto diag = connect.emitError(
"destination cannot be driven by multiple "
4307 diag.attachNote(c->getLoc()) <<
"other driver is here";
4314LogicalResult ConnectOp::verify() {
4315 auto dstType = getDest().getType();
4316 auto srcType = getSrc().getType();
4317 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4318 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4319 if (!dstBaseType || !srcBaseType) {
4320 if (dstType != srcType)
4321 return emitError(
"may not connect different non-base types");
4324 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4325 return emitError(
"analog types may not be connected");
4329 return emitError(
"type mismatch between destination ")
4330 << dstBaseType <<
" and source " << srcBaseType;
4335 return emitError(
"destination ")
4336 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4349LogicalResult MatchingConnectOp::verify() {
4350 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4351 auto baseType = type_cast<FIRRTLBaseType>(type);
4354 if (baseType && baseType.containsAnalog())
4355 return emitError(
"analog types may not be connected");
4360 "`SameAnonTypeOperands` trait should have already rejected "
4361 "structurally non-equivalent types");
4374LogicalResult RefDefineOp::verify() {
4381 if (
auto *op = getDest().getDefiningOp()) {
4383 if (isa<RefSubOp>(op))
4385 "destination reference cannot be a sub-element of a reference");
4386 if (isa<RefCastOp>(op))
4388 "destination reference cannot be a cast of another reference");
4396 SmallVector<SymbolRefAttr> missingLayers;
4399 "has more layer requirements than destination",
4400 "additional layers required");
4403LogicalResult PropAssignOp::verify() {
4413LogicalResult PropertyAssertOp::verify() {
4416 if (
auto *defOp = getCondition().getDefiningOp())
4417 if (
auto boolConst = dyn_cast<BoolConstantOp>(defOp))
4418 if (!boolConst.getValue())
4419 return emitOpError(
"property assertion is statically false: ")
4425 auto domainType = dyn_cast<DomainType>(value.getType());
4430 return domainType.getName();
4433LogicalResult DomainDefineOp::verify() {
4440 auto dst = getDest();
4441 auto src = getSrc();
4449 if (
auto *srcDefOp = src.getDefiningOp())
4450 if (isa<WireOp>(srcDefOp))
4452 if (
auto *dstDefOp = dst.getDefiningOp())
4453 if (isa<WireOp>(dstDefOp))
4458 return emitError(
"could not determine domain-type of destination");
4462 return emitError(
"could not determine domain-type of source");
4464 if (dstDomain != srcDomain) {
4465 auto diag = emitError()
4466 <<
"source domain type " << srcDomain
4467 <<
" does not match destination domain type " << dstDomain;
4474void WhenOp::createElseRegion() {
4475 assert(!hasElseRegion() &&
"already has an else region");
4476 getElseRegion().push_back(
new Block());
4479void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4480 bool withElseRegion, std::function<
void()> thenCtor,
4481 std::function<
void()> elseCtor) {
4482 OpBuilder::InsertionGuard guard(builder);
4483 result.addOperands(condition);
4486 builder.createBlock(result.addRegion());
4491 Region *elseRegion = result.addRegion();
4492 if (withElseRegion) {
4493 builder.createBlock(elseRegion);
4503LogicalResult MatchOp::verify() {
4504 FEnumType type = getInput().getType();
4507 auto numCases = getTags().size();
4508 auto numRegions = getNumRegions();
4509 if (numRegions != numCases)
4510 return emitOpError(
"expected ")
4511 << numRegions <<
" tags but got " << numCases;
4513 auto numTags = type.getNumElements();
4515 SmallDenseSet<int64_t> seen;
4516 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4517 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4520 if (region.getNumArguments() != 1)
4521 return emitOpError(
"region should have exactly one argument");
4524 if (tagIndex >= numTags)
4525 return emitOpError(
"the tag index ")
4526 << tagIndex <<
" is out of the range of valid tags in " << type;
4529 auto [it, inserted] = seen.insert(tagIndex);
4531 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4532 <<
" is matched more than once";
4535 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4536 auto regionType = region.getArgument(0).getType();
4537 if (regionType != expectedType)
4538 return emitOpError(
"region type ")
4539 << regionType <<
" does not match the expected type "
4544 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4545 if (!seen.contains(i))
4546 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4551void MatchOp::print(OpAsmPrinter &p) {
4552 auto input = getInput();
4553 FEnumType type = input.getType();
4554 auto regions = getRegions();
4555 p <<
" " << input <<
" : " << type;
4556 SmallVector<StringRef> elided = {
"tags"};
4557 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4560 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4563 p.printKeywordOrString(
4564 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4566 p.printRegionArgument(region.front().getArgument(0), {},
4569 p.printRegion(region,
false);
4576ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4577 auto *
context = parser.getContext();
4578 auto &properties = result.getOrAddProperties<Properties>();
4579 OpAsmParser::UnresolvedOperand input;
4580 if (parser.parseOperand(input) || parser.parseColon())
4583 auto loc = parser.getCurrentLocation();
4585 if (parser.parseType(type))
4587 auto enumType = type_dyn_cast<FEnumType>(type);
4589 return parser.emitError(loc,
"expected enumeration type but got") << type;
4591 if (parser.resolveOperand(input, type, result.operands) ||
4592 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4593 parser.parseLBrace())
4596 auto i32Type = IntegerType::get(
context, 32);
4597 SmallVector<Attribute> tags;
4600 if (failed(parser.parseOptionalKeyword(
"case")))
4604 auto nameLoc = parser.getCurrentLocation();
4606 OpAsmParser::Argument arg;
4607 auto *region = result.addRegion();
4608 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4609 parser.parseArgument(arg) || parser.parseRParen())
4613 auto index = enumType.getElementIndex(name);
4615 return parser.emitError(nameLoc,
"the tag \"")
4616 << name <<
"\" is not a member of the enumeration " << enumType;
4617 tags.push_back(IntegerAttr::get(i32Type, *index));
4620 arg.type = enumType.getElementTypePreservingConst(*index);
4621 if (parser.parseRegion(*region, arg))
4624 properties.setTags(ArrayAttr::get(
context, tags));
4626 return parser.parseRBrace();
4629void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4631 MutableArrayRef<std::unique_ptr<Region>> regions) {
4632 auto &properties = result.getOrAddProperties<Properties>();
4633 result.addOperands(input);
4634 properties.setTags(tags);
4635 result.addRegions(regions);
4644 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4645 bool visitInvalidExpr(Operation *op) {
return false; }
4646 bool visitUnhandledExpr(Operation *op) {
return true; }
4652void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4655 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4656 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4657 auto width = ty.getWidthOrSentinel();
4661 name = (Twine(base) + Twine(width)).str();
4662 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4663 auto width = ty.getWidthOrSentinel();
4665 name =
"invalid_analog";
4667 name = (
"invalid_analog" + Twine(width)).str();
4668 }
else if (type_isa<AsyncResetType>(getType()))
4669 name =
"invalid_asyncreset";
4670 else if (type_isa<ResetType>(getType()))
4671 name =
"invalid_reset";
4672 else if (type_isa<ClockType>(getType()))
4673 name =
"invalid_clock";
4677 setNameFn(getResult(), name);
4680void ConstantOp::print(OpAsmPrinter &p) {
4682 p.printAttributeWithoutType(getValueAttr());
4684 p.printType(getType());
4685 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4688ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4689 auto &properties = result.getOrAddProperties<Properties>();
4692 auto loc = parser.getCurrentLocation();
4693 auto valueResult = parser.parseOptionalInteger(value);
4694 if (!valueResult.has_value())
4695 return parser.emitError(loc,
"expected integer value");
4699 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4700 parser.parseOptionalAttrDict(result.attributes))
4702 result.addTypes(resultType);
4708 if (width > value.getBitWidth()) {
4712 value = value.sext(width);
4713 }
else if (width < value.getBitWidth()) {
4716 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4717 : value.getActiveBits();
4718 if (width < neededBits)
4719 return parser.emitError(loc,
"constant out of range for result type ")
4721 value = value.trunc(width);
4725 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4727 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4728 properties.setValue(valueAttr);
4732LogicalResult ConstantOp::verify() {
4736 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4738 "firrtl.constant attribute bitwidth doesn't match return type");
4741 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4742 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4743 return emitError(
"firrtl.constant attribute has wrong sign");
4750void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4751 const APInt &value) {
4754 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4755 "incorrect attribute bitwidth for firrtl.constant");
4758 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4759 return build(builder, result, type, attr);
4764void ConstantOp::build(OpBuilder &builder, OperationState &result,
4765 const APSInt &value) {
4766 auto attr = IntegerAttr::get(builder.getContext(), value);
4768 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4769 return build(builder, result, type, attr);
4772void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4779 SmallString<32> specialNameBuffer;
4780 llvm::raw_svector_ostream specialName(specialNameBuffer);
4782 getValue().print(specialName, intTy.
isSigned());
4784 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4787 specialName << width;
4788 setNameFn(getResult(), specialName.str());
4791void SpecialConstantOp::print(OpAsmPrinter &p) {
4794 p << static_cast<unsigned>(getValue());
4796 p.printType(getType());
4797 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4800ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4801 OperationState &result) {
4802 auto &properties = result.getOrAddProperties<Properties>();
4806 auto loc = parser.getCurrentLocation();
4807 auto valueResult = parser.parseOptionalInteger(value);
4808 if (!valueResult.has_value())
4809 return parser.emitError(loc,
"expected integer value");
4812 if (value != 0 && value != 1)
4813 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4817 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4818 parser.parseOptionalAttrDict(result.attributes))
4820 result.addTypes(resultType);
4823 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4824 properties.setValue(valueAttr);
4828void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4829 SmallString<32> specialNameBuffer;
4830 llvm::raw_svector_ostream specialName(specialNameBuffer);
4832 specialName << static_cast<unsigned>(getValue());
4833 auto type = getType();
4834 if (type_isa<ClockType>(type)) {
4835 specialName <<
"_clock";
4836 }
else if (type_isa<ResetType>(type)) {
4837 specialName <<
"_reset";
4838 }
else if (type_isa<AsyncResetType>(type)) {
4839 specialName <<
"_asyncreset";
4841 setNameFn(getResult(), specialName.str());
4848 if (type.isGround()) {
4849 if (!isa<IntegerAttr>(attr)) {
4850 op->emitOpError(
"Ground type is not an integer attribute");
4855 auto attrlist = dyn_cast<ArrayAttr>(attr);
4857 op->emitOpError(
"expected array attribute for aggregate constant");
4860 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4861 if (array.getNumElements() != attrlist.size()) {
4862 op->emitOpError(
"array attribute (")
4863 << attrlist.size() <<
") has wrong size for vector constant ("
4864 << array.getNumElements() <<
")";
4867 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4871 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4872 if (bundle.getNumElements() != attrlist.size()) {
4873 op->emitOpError(
"array attribute (")
4874 << attrlist.size() <<
") has wrong size for bundle constant ("
4875 << bundle.getNumElements() <<
")";
4878 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4879 if (bundle.getElement(i).isFlip) {
4880 op->emitOpError(
"Cannot have constant bundle type with flip");
4888 op->emitOpError(
"Unknown aggregate type");
4892LogicalResult AggregateConstantOp::verify() {
4898Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4900 Attribute value = getFields();
4901 while (fieldID != 0) {
4902 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4903 auto index = bundle.getIndexForFieldID(fieldID);
4904 fieldID -= bundle.getFieldID(index);
4905 type = bundle.getElementType(index);
4906 value = cast<ArrayAttr>(value)[index];
4908 auto vector = type_cast<FVectorType>(type);
4909 auto index = vector.getIndexForFieldID(fieldID);
4910 fieldID -= vector.getFieldID(index);
4911 type = vector.getElementType();
4912 value = cast<ArrayAttr>(value)[index];
4918LogicalResult FIntegerConstantOp::verify() {
4919 auto i = getValueAttr();
4920 if (!i.getType().isSignedInteger())
4921 return emitOpError(
"value must be signed");
4925void FIntegerConstantOp::print(OpAsmPrinter &p) {
4927 p.printAttributeWithoutType(getValueAttr());
4928 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4931ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4932 OperationState &result) {
4933 auto *
context = parser.getContext();
4934 auto &properties = result.getOrAddProperties<Properties>();
4936 if (parser.parseInteger(value) ||
4937 parser.parseOptionalAttrDict(result.attributes))
4939 result.addTypes(FIntegerType::get(
context));
4941 IntegerType::get(
context, value.getBitWidth(), IntegerType::Signed);
4942 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4943 properties.setValue(valueAttr);
4947ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4948 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4951 if (parser.parseOperandList(operands) ||
4952 parser.parseOptionalAttrDict(result.attributes) ||
4953 parser.parseColonType(type))
4955 result.addTypes(type);
4957 return parser.resolveOperands(operands, type.getElementType(),
4961void ListCreateOp::print(OpAsmPrinter &p) {
4963 p.printOperands(getElements());
4964 p.printOptionalAttrDict((*this)->getAttrs());
4965 p <<
" : " << getType();
4968LogicalResult ListCreateOp::verify() {
4969 if (getElements().
empty())
4972 auto elementType = getElements().front().getType();
4973 auto listElementType = getType().getElementType();
4975 return emitOpError(
"has elements of type ")
4976 <<
elementType <<
" instead of " << listElementType;
4981LogicalResult BundleCreateOp::verify() {
4982 BundleType resultType = getType();
4983 if (resultType.getNumElements() != getFields().size())
4984 return emitOpError(
"number of fields doesn't match type");
4985 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4987 resultType.getElementTypePreservingConst(i),
4988 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4989 return emitOpError(
"type of element doesn't match bundle for field ")
4990 << resultType.getElement(i).name;
4995LogicalResult VectorCreateOp::verify() {
4996 FVectorType resultType = getType();
4997 if (resultType.getNumElements() != getFields().size())
4998 return emitOpError(
"number of fields doesn't match type");
4999 auto elemTy = resultType.getElementTypePreservingConst();
5000 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
5002 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
5003 return emitOpError(
"type of element doesn't match vector element");
5009UnknownValueOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
5011 auto classType = dyn_cast<ClassType>(getType());
5015 auto className = classType.getNameAttr();
5017 Operation *op = symbolTable.lookupNearestSymbolFrom(*
this, className);
5019 return emitOpError() <<
"refers to non-existent class ("
5020 << className.getAttr() <<
")";
5023 if (!isa<ClassLike>(op))
5024 return emitOpError() <<
"refers to a non-class type ("
5025 << className.getAttr() <<
")";
5034LogicalResult FEnumCreateOp::verify() {
5035 FEnumType resultType = getResult().getType();
5036 auto elementIndex = resultType.getElementIndex(
getFieldName());
5038 return emitOpError(
"label ")
5039 <<
getFieldName() <<
" is not a member of the enumeration type "
5042 resultType.getElementTypePreservingConst(*elementIndex),
5043 getInput().getType()))
5044 return emitOpError(
"type of element doesn't match enum element");
5048void FEnumCreateOp::print(OpAsmPrinter &printer) {
5051 printer <<
'(' << getInput() <<
')';
5052 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
5053 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
5055 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
5056 ArrayRef<Type>{getResult().getType()});
5059ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
5060 auto *
context = parser.getContext();
5061 auto &properties = result.getOrAddProperties<Properties>();
5063 OpAsmParser::UnresolvedOperand input;
5064 std::string fieldName;
5065 mlir::FunctionType functionType;
5066 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
5067 parser.parseOperand(input) || parser.parseRParen() ||
5068 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5069 parser.parseType(functionType))
5072 if (functionType.getNumInputs() != 1)
5073 return parser.emitError(parser.getNameLoc(),
"single input type required");
5074 if (functionType.getNumResults() != 1)
5075 return parser.emitError(parser.getNameLoc(),
"single result type required");
5077 auto inputType = functionType.getInput(0);
5078 if (parser.resolveOperand(input, inputType, result.operands))
5081 auto outputType = functionType.getResult(0);
5082 auto enumType = type_dyn_cast<FEnumType>(outputType);
5084 return parser.emitError(parser.getNameLoc(),
5085 "output must be enum type, got ")
5087 auto fieldIndex = enumType.getElementIndex(fieldName);
5089 return parser.emitError(parser.getNameLoc(),
5090 "unknown field " + fieldName +
" in enum type ")
5093 properties.setFieldIndex(
5094 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5096 result.addTypes(enumType);
5105LogicalResult IsTagOp::verify() {
5106 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5107 return emitOpError(
"element index is greater than the number of fields in "
5112void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
5113 printer <<
' ' << getInput() <<
' ';
5115 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
5116 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5117 printer <<
" : " << getInput().getType();
5120ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
5121 auto *
context = parser.getContext();
5122 auto &properties = result.getOrAddProperties<Properties>();
5124 OpAsmParser::UnresolvedOperand input;
5125 std::string fieldName;
5127 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
5128 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5129 parser.parseType(inputType))
5132 if (parser.resolveOperand(input, inputType, result.operands))
5135 auto enumType = type_dyn_cast<FEnumType>(inputType);
5137 return parser.emitError(parser.getNameLoc(),
5138 "input must be enum type, got ")
5140 auto fieldIndex = enumType.getElementIndex(fieldName);
5142 return parser.emitError(parser.getNameLoc(),
5143 "unknown field " + fieldName +
" in enum type ")
5146 properties.setFieldIndex(
5147 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5149 result.addTypes(UIntType::get(
context, 1,
false));
5154FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5155 PropertyRef properties,
5156 mlir::RegionRange regions,
5157 std::optional<Location> loc) {
5158 Adaptor adaptor(operands, attrs, properties, regions);
5159 return UIntType::get(attrs.getContext(), 1,
5160 isConst(adaptor.getInput().getType()));
5163template <
typename OpTy>
5165 auto *
context = parser.getContext();
5167 OpAsmParser::UnresolvedOperand input;
5168 std::string fieldName;
5170 if (parser.parseOperand(input) || parser.parseLSquare() ||
5171 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5172 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5173 parser.parseType(inputType))
5176 if (parser.resolveOperand(input, inputType, result.operands))
5179 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
5181 return parser.emitError(parser.getNameLoc(),
5182 "input must be bundle type, got ")
5184 auto fieldIndex = bundleType.getElementIndex(fieldName);
5186 return parser.emitError(parser.getNameLoc(),
5187 "unknown field " + fieldName +
" in bundle type ")
5190 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
5191 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5193 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
5196 result.addTypes(type);
5201ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
5202 auto *
context = parser.getContext();
5204 OpAsmParser::UnresolvedOperand input;
5205 std::string fieldName;
5207 if (parser.parseOperand(input) || parser.parseLSquare() ||
5208 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5209 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5210 parser.parseType(inputType))
5213 if (parser.resolveOperand(input, inputType, result.operands))
5216 auto enumType = type_dyn_cast<FEnumType>(inputType);
5218 return parser.emitError(parser.getNameLoc(),
5219 "input must be enum type, got ")
5221 auto fieldIndex = enumType.getElementIndex(fieldName);
5223 return parser.emitError(parser.getNameLoc(),
5224 "unknown field " + fieldName +
" in enum type ")
5227 result.getOrAddProperties<Properties>().setFieldIndex(
5228 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
5230 SmallVector<Type> inferredReturnTypes;
5231 if (failed(SubtagOp::inferReturnTypes(
5232 context, result.location, result.operands,
5233 result.attributes.getDictionary(
context), result.getRawProperties(),
5234 result.regions, inferredReturnTypes)))
5236 result.addTypes(inferredReturnTypes);
5241ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5242 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
5244ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
5245 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
5248template <
typename OpTy>
5250 printer <<
' ' << op.getInput() <<
'[';
5251 printer.printKeywordOrString(op.getFieldName());
5253 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5254 elidedAttrs.push_back(
"fieldIndex");
5255 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5256 printer <<
" : " << op.getInput().getType();
5258void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5259 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
5261void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
5262 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
5265void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
5266 printer <<
' ' << getInput() <<
'[';
5269 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
5270 elidedAttrs.push_back(
"fieldIndex");
5271 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
5272 printer <<
" : " << getInput().getType();
5275template <
typename OpTy>
5277 if (op.getFieldIndex() >=
5278 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
5280 return op.emitOpError(
"subfield element index is greater than the number "
5281 "of fields in the bundle type");
5284LogicalResult SubfieldOp::verify() {
5285 return verifySubfieldLike<SubfieldOp>(*
this);
5287LogicalResult OpenSubfieldOp::verify() {
5288 return verifySubfieldLike<OpenSubfieldOp>(*
this);
5291LogicalResult SubtagOp::verify() {
5292 if (getFieldIndex() >= getInput().getType().base().getNumElements())
5293 return emitOpError(
"subfield element index is greater than the number "
5294 "of fields in the bundle type");
5304 SmallVector<Operation *, 8> worklist({op});
5308 bool constant =
true;
5314 while (constant && !(worklist.empty()))
5315 TypeSwitch<Operation *>(worklist.pop_back_val())
5316 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5317 if (
auto definingOp = op.getInput().getDefiningOp())
5318 worklist.push_back(definingOp);
5321 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5322 for (
auto &use : op.getResult().getUses())
5323 worklist.push_back(use.getOwner());
5325 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5326 .Default([&](
auto) { constant =
false; });
5335 if (
auto *op = value.getDefiningOp())
5340LogicalResult ConstCastOp::verify() {
5342 return emitOpError() << getInput().getType()
5343 <<
" is not 'const'-castable to "
5344 << getResult().getType();
5348FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5349 std::optional<Location> loc) {
5350 auto inType = type_cast<BundleType>(type);
5352 if (fieldIndex >= inType.getNumElements())
5354 "subfield element index is greater than the "
5355 "number of fields in the bundle type");
5359 return inType.getElementTypePreservingConst(fieldIndex);
5362FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5363 std::optional<Location> loc) {
5364 auto inType = type_cast<OpenBundleType>(type);
5366 if (fieldIndex >= inType.getNumElements())
5368 "subfield element index is greater than the "
5369 "number of fields in the bundle type");
5373 return inType.getElementTypePreservingConst(fieldIndex);
5376bool SubfieldOp::isFieldFlipped() {
5377 BundleType bundle = getInput().getType();
5378 return bundle.getElement(getFieldIndex()).isFlip;
5380bool OpenSubfieldOp::isFieldFlipped() {
5381 auto bundle = getInput().getType();
5382 return bundle.getElement(getFieldIndex()).isFlip;
5385FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5386 std::optional<Location> loc) {
5387 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5388 if (fieldIndex < vectorType.getNumElements())
5389 return vectorType.getElementTypePreservingConst();
5391 "' in vector type ", type);
5396FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5397 std::optional<Location> loc) {
5398 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5399 if (fieldIndex < vectorType.getNumElements())
5400 return vectorType.getElementTypePreservingConst();
5402 "' in vector type ", type);
5408FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5409 PropertyRef properties,
5410 mlir::RegionRange regions,
5411 std::optional<Location> loc) {
5412 Adaptor adaptor(operands, attrs, properties, regions);
5413 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5414 auto fieldIndex = adaptor.getFieldIndex();
5416 if (fieldIndex >= inType.getNumElements())
5418 "subtag element index is greater than the "
5419 "number of fields in the enum type");
5423 auto elementType = inType.getElement(fieldIndex).type;
5427FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5428 std::optional<Location> loc) {
5429 if (!type_isa<UIntType>(indexType))
5433 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5435 return vectorType.getElementTypePreservingConst();
5436 return vectorType.getElementType().getAllConstDroppedType();
5444 std::optional<Location> loc) {
5445 auto inType = type_cast<FEnumType>(input);
5446 return UIntType::get(inType.getContext(), inType.getTagWidth());
5449ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5450 OpAsmParser::UnresolvedOperand index;
5451 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5452 Type indexType, elemType;
5454 if (parser.parseOperand(index) || parser.parseComma() ||
5455 parser.parseOperandList(inputs) ||
5456 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5457 parser.parseType(indexType) || parser.parseComma() ||
5458 parser.parseType(elemType))
5461 if (parser.resolveOperand(index, indexType, result.operands))
5464 result.addTypes(elemType);
5466 return parser.resolveOperands(inputs, elemType, result.operands);
5469void MultibitMuxOp::print(OpAsmPrinter &p) {
5470 p <<
" " << getIndex() <<
", ";
5471 p.printOperands(getInputs());
5472 p.printOptionalAttrDict((*this)->getAttrs());
5473 p <<
" : " << getIndex().getType() <<
", " << getType();
5476FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5477 DictionaryAttr attrs,
5478 PropertyRef properties,
5479 mlir::RegionRange regions,
5480 std::optional<Location> loc) {
5481 if (operands.size() < 2)
5485 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5486 return operands[1].getType() == op.getType();
5490 return type_cast<FIRRTLType>(operands[1].getType());
5497LogicalResult ObjectSubfieldOp::inferReturnTypes(
5498 MLIRContext *
context, std::optional<mlir::Location> location,
5499 ValueRange operands, DictionaryAttr attributes, PropertyRef properties,
5500 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5502 inferReturnType(operands, attributes, properties, regions, location);
5505 inferredReturnTypes.push_back(type);
5509Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5510 std::optional<Location> loc) {
5511 auto classType = dyn_cast<ClassType>(inType);
5515 if (classType.getNumElements() <= fieldIndex)
5517 "number of fields in the object");
5518 return classType.getElement(fieldIndex).type;
5521void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5522 auto input = getInput();
5523 auto classType = input.getType();
5524 p <<
' ' << input <<
"[";
5525 p.printKeywordOrString(classType.getElement(getIndex()).name);
5527 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5528 p <<
" : " << classType;
5531ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5532 OperationState &result) {
5533 auto *
context = parser.getContext();
5535 OpAsmParser::UnresolvedOperand input;
5536 std::string fieldName;
5537 ClassType inputType;
5538 if (parser.parseOperand(input) || parser.parseLSquare() ||
5539 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5540 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5541 parser.parseType(inputType) ||
5542 parser.resolveOperand(input, inputType, result.operands))
5545 auto index = inputType.getElementIndex(fieldName);
5547 return parser.emitError(parser.getNameLoc(),
5548 "unknown field " + fieldName +
" in class type ")
5550 result.getOrAddProperties<Properties>().setIndex(
5551 IntegerAttr::get(IntegerType::get(
context, 32), *index));
5553 SmallVector<Type> inferredReturnTypes;
5554 if (failed(inferReturnTypes(
context, result.location, result.operands,
5555 result.attributes.getDictionary(
context),
5556 result.getRawProperties(), result.regions,
5557 inferredReturnTypes)))
5559 result.addTypes(inferredReturnTypes);
5576 int32_t &rhsWidth,
bool &isConstResult,
5577 std::optional<Location> loc) {
5579 auto lhsi = type_dyn_cast<IntType>(lhs);
5580 auto rhsi = type_dyn_cast<IntType>(rhs);
5581 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5584 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5586 else if (!lhsi && rhsi)
5587 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5589 else if (!lhsi && !rhsi)
5590 mlir::emitError(*loc,
"operands must be integer types, not ")
5591 << lhs <<
" and " << rhs;
5593 mlir::emitError(*loc,
"operand signedness must match");
5598 lhsWidth = lhsi.getWidthOrSentinel();
5599 rhsWidth = rhsi.getWidthOrSentinel();
5600 isConstResult = lhsi.isConst() && rhsi.isConst();
5605 assert(op->getNumOperands() == 2 &&
5606 "SameOperandsIntTypeKind on non-binary op");
5607 int32_t lhsWidth, rhsWidth;
5610 op->getOperand(1).getType(), lhsWidth,
5611 rhsWidth, isConstResult, op->getLoc()));
5615 std::optional<Location> loc) {
5616 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5617 bool isConstResult =
false;
5621 if (lhsWidth != -1 && rhsWidth != -1)
5622 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5623 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5628 std::optional<Location> loc) {
5629 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5630 bool isConstResult =
false;
5634 if (lhsWidth != -1 && rhsWidth != -1)
5635 resultWidth = lhsWidth + rhsWidth;
5637 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5642 std::optional<Location> loc) {
5643 int32_t lhsWidth, rhsWidth;
5644 bool isConstResult =
false;
5649 if (type_isa<UIntType>(lhs))
5650 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5653 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5654 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5658 std::optional<Location> loc) {
5659 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5660 bool isConstResult =
false;
5664 if (lhsWidth != -1 && rhsWidth != -1)
5665 resultWidth = std::min(lhsWidth, rhsWidth);
5666 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5671 std::optional<Location> loc) {
5672 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5673 bool isConstResult =
false;
5677 if (lhsWidth != -1 && rhsWidth != -1) {
5678 resultWidth = std::max(lhsWidth, rhsWidth);
5679 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5682 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5686 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5690 std::optional<Location> loc) {
5691 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5694 auto lhsVec = type_cast<FVectorType>(lhs);
5695 auto rhsVec = type_cast<FVectorType>(rhs);
5697 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5702 rhsVec.getElementTypePreservingConst(), loc);
5705 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5706 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5707 lhsVec.isConst() && rhsVec.isConst() &&
5708 elemBaseType.isConst());
5712 std::optional<Location> loc) {
5713 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5716FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5717 PropertyRef properties,
5718 mlir::RegionRange regions,
5719 std::optional<Location> loc) {
5721 if (operands.empty())
5722 return UIntType::get(attrs.getContext(), 0);
5725 bool isSigned = type_isa<SIntType>(operands[0].getType());
5726 for (
auto operand : operands) {
5727 auto type = type_dyn_cast<IntType>(operand.getType());
5730 if (type.isSigned() != isSigned)
5732 "all operands must have same signedness");
5736 int32_t resultWidth = 0;
5737 bool isConstResult =
true;
5739 for (
auto operand : operands) {
5740 auto type = type_cast<IntType>(operand.getType());
5741 int32_t width = type.getWidthOrSentinel();
5748 if (resultWidth != -1)
5749 resultWidth += width;
5752 isConstResult &= type.isConst();
5756 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5760 std::optional<Location> loc) {
5761 auto lhsi = type_dyn_cast<IntType>(lhs);
5762 auto rhsui = type_dyn_cast<UIntType>(rhs);
5763 if (!rhsui || !lhsi)
5765 loc,
"first operand should be integer, second unsigned int");
5769 auto width = lhsi.getWidthOrSentinel();
5770 if (width == -1 || !rhsui.getWidth().has_value()) {
5773 auto amount = *rhsui.getWidth();
5776 "shift amount too large: second operand of "
5777 "dshl is wider than 31 bits");
5778 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5779 if (newWidth > INT32_MAX)
5781 loc,
"shift amount too large: first operand shifted by maximum "
5782 "amount exceeds maximum width");
5785 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5786 lhsi.
isConst() && rhsui.isConst());
5790 std::optional<Location> loc) {
5791 auto lhsi = type_dyn_cast<IntType>(lhs);
5792 auto rhsu = type_dyn_cast<UIntType>(rhs);
5795 loc,
"first operand should be integer, second unsigned int");
5796 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5800 std::optional<Location> loc) {
5801 auto lhsi = type_dyn_cast<IntType>(lhs);
5802 auto rhsu = type_dyn_cast<UIntType>(rhs);
5805 loc,
"first operand should be integer, second unsigned int");
5806 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5814 std::optional<Location> loc) {
5815 return UIntType::get(input.getContext(), 32);
5819 std::optional<Location> loc) {
5820 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5823 int32_t width = base.getBitWidthOrSentinel();
5826 return SIntType::get(input.getContext(), width, base.
isConst());
5830 std::optional<Location> loc) {
5831 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5834 int32_t width = base.getBitWidthOrSentinel();
5837 return UIntType::get(input.getContext(), width, base.
isConst());
5841 std::optional<Location> loc) {
5842 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5845 "operand must be single bit scalar base type");
5846 int32_t width = base.getBitWidthOrSentinel();
5847 if (width == -2 || width == 0 || width > 1)
5849 return AsyncResetType::get(input.getContext(), base.
isConst());
5853 std::optional<Location> loc) {
5854 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5857 return ResetType::get(input.getContext(), base.
isConst());
5861 std::optional<Location> loc) {
5862 return ClockType::get(input.getContext(),
isConst(input));
5866 std::optional<Location> loc) {
5867 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5868 auto width = uiType.getWidthOrSentinel();
5871 return SIntType::get(input.getContext(), width, uiType.
isConst());
5874 if (type_isa<SIntType>(input))
5881 std::optional<Location> loc) {
5882 auto inputi = type_dyn_cast<IntType>(input);
5885 int32_t width = inputi.getWidthOrSentinel();
5888 return SIntType::get(input.getContext(), width, inputi.
isConst());
5892 std::optional<Location> loc) {
5893 auto inputi = type_dyn_cast<IntType>(input);
5896 if (isa<UIntType>(inputi))
5898 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5903 std::optional<Location> loc) {
5904 return UIntType::get(input.getContext(), 1,
isConst(input));
5913 std::optional<Location> loc) {
5914 auto inputi = type_dyn_cast<IntType>(input);
5917 loc,
"input type should be the int type but got ", input);
5922 loc,
"high must be equal or greater than low, but got high = ", high,
5930 int32_t width = inputi.getWidthOrSentinel();
5931 if (width != -1 && high >= width)
5934 "high must be smaller than the width of input, but got high = ", high,
5935 ", width = ", width);
5937 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5941 std::optional<Location> loc) {
5943 auto inputi = type_dyn_cast<IntType>(input);
5944 if (amount < 0 || !inputi)
5946 loc,
"operand must have integer type and amount must be >= 0");
5948 int32_t width = inputi.getWidthOrSentinel();
5949 if (width != -1 && amount > width)
5952 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5967 bool isConstCondition,
5968 std::optional<Location> loc) {
5974 if (high.getTypeID() != low.getTypeID())
5975 return emitInferRetTypeError<FIRRTLBaseType>(
5976 loc,
"incompatible mux operand types, true value type: ", high,
5977 ", false value type: ", low);
5979 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5984 if (type_isa<IntType>(low)) {
5989 if (highWidth == -1)
5991 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5996 auto highEnum = type_dyn_cast<FEnumType>(high);
5997 auto lowEnum = type_dyn_cast<FEnumType>(low);
5998 if (lowEnum && highEnum) {
5999 if (lowEnum.getNumElements() != highEnum.getNumElements())
6000 return emitInferRetTypeError<FIRRTLBaseType>(
6001 loc,
"incompatible mux operand types, true value type: ", high,
6002 ", false value type: ", low);
6003 SmallVector<FEnumType::EnumElement> elements;
6004 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
6006 if (high.name != low.name || high.value != low.value)
6007 return emitInferRetTypeError<FIRRTLBaseType>(
6008 loc,
"incompatible mux operand types, true value type: ", highEnum,
6009 ", false value type: ", lowEnum);
6016 elements.emplace_back(high.name, high.value, inner);
6018 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
6022 auto highVector = type_dyn_cast<FVectorType>(high);
6023 auto lowVector = type_dyn_cast<FVectorType>(low);
6024 if (highVector && lowVector &&
6025 highVector.getNumElements() == lowVector.getNumElements()) {
6027 lowVector.getElementTypePreservingConst(),
6028 isConstCondition, loc);
6031 return FVectorType::get(inner, lowVector.getNumElements(),
6036 auto highBundle = type_dyn_cast<BundleType>(high);
6037 auto lowBundle = type_dyn_cast<BundleType>(low);
6038 if (highBundle && lowBundle) {
6039 auto highElements = highBundle.getElements();
6040 auto lowElements = lowBundle.getElements();
6043 SmallVector<BundleType::BundleElement> newElements;
6045 bool failed =
false;
6047 if (highElements[i].name != lowElements[i].name ||
6048 highElements[i].isFlip != lowElements[i].isFlip) {
6052 auto element = highElements[i];
6054 highBundle.getElementTypePreservingConst(i),
6055 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
6058 newElements.push_back(element);
6061 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
6063 return emitInferRetTypeError<FIRRTLBaseType>(
6064 loc,
"incompatible mux operand bundle fields, true value type: ", high,
6065 ", false value type: ", low);
6070 return emitInferRetTypeError<FIRRTLBaseType>(
6071 loc,
"invalid mux operand types, true value type: ", high,
6072 ", false value type: ", low);
6077 std::optional<Location> loc) {
6078 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
6079 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
6080 if (!highType || !lowType)
6085FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
6086 DictionaryAttr attrs,
6087 PropertyRef properties,
6088 mlir::RegionRange regions,
6089 std::optional<Location> loc) {
6090 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
6091 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
6092 if (!highType || !lowType)
6098FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
6099 DictionaryAttr attrs,
6100 PropertyRef properties,
6101 mlir::RegionRange regions,
6102 std::optional<Location> loc) {
6103 SmallVector<FIRRTLBaseType> types;
6105 for (
unsigned i = 1; i < 5; i++) {
6106 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
6111 isConst(operands[0].getType()), loc);
6115 result = types.back();
6122 std::optional<Location> loc) {
6123 auto inputi = type_dyn_cast<IntType>(input);
6124 if (amount < 0 || !inputi)
6126 loc,
"pad input must be integer and amount must be >= 0");
6128 int32_t width = inputi.getWidthOrSentinel();
6132 width = std::max<int32_t>(width, amount);
6133 return IntType::get(input.getContext(), inputi.isSigned(), width,
6138 std::optional<Location> loc) {
6139 auto inputi = type_dyn_cast<IntType>(input);
6140 if (amount < 0 || !inputi)
6142 loc,
"shl input must be integer and amount must be >= 0");
6144 int32_t width = inputi.getWidthOrSentinel();
6148 return IntType::get(input.getContext(), inputi.isSigned(), width,
6153 std::optional<Location> loc) {
6154 auto inputi = type_dyn_cast<IntType>(input);
6155 if (amount < 0 || !inputi)
6157 loc,
"shr input must be integer and amount must be >= 0");
6159 int32_t width = inputi.getWidthOrSentinel();
6162 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
6163 width = std::max<int32_t>(minWidth, width - amount);
6166 return IntType::get(input.getContext(), inputi.isSigned(), width,
6171 std::optional<Location> loc) {
6173 auto inputi = type_dyn_cast<IntType>(input);
6174 if (amount < 0 || !inputi)
6176 loc,
"tail input must be integer and amount must be >= 0");
6178 int32_t width = inputi.getWidthOrSentinel();
6182 loc,
"amount must be less than or equal operand width");
6193void VerbatimExprOp::getAsmResultNames(
6194 function_ref<
void(Value, StringRef)> setNameFn) {
6198 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6199 auto name = getText();
6201 if (name.starts_with(
"`"))
6202 name = name.drop_front();
6203 name = name.take_while(isOkCharacter);
6205 setNameFn(getResult(), name);
6212void VerbatimWireOp::getAsmResultNames(
6213 function_ref<
void(Value, StringRef)> setNameFn) {
6217 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
6218 auto name = getText();
6220 if (name.starts_with(
"`"))
6221 name = name.drop_front();
6222 name = name.take_while(isOkCharacter);
6224 setNameFn(getResult(), name);
6235 op->emitError() <<
"unknown width is not allowed for DPI";
6236 return WalkResult::interrupt();
6238 if (width == 1 || width == 8 || width == 16 || width == 32 ||
6240 return WalkResult::advance();
6242 <<
"integer types used by DPI functions must have a "
6243 "specific bit width; "
6244 "it must be equal to 1(bit), 8(byte), 16(shortint), "
6245 "32(int), 64(longint) "
6246 "or greater than 64, but got "
6248 return WalkResult::interrupt();
6253LogicalResult DPICallIntrinsicOp::verify() {
6254 if (
auto inputNames = getInputNames()) {
6255 if (getInputs().size() != inputNames->size())
6256 return emitError() <<
"inputNames has " << inputNames->size()
6257 <<
" elements but there are " << getInputs().size()
6258 <<
" input arguments";
6260 if (
auto outputName = getOutputName())
6261 if (getNumResults() == 0)
6262 return emitError() <<
"output name is given but there is no result";
6264 auto checkType = [
this](Type type) {
6267 return success(llvm::all_of(this->getResultTypes(), checkType) &&
6268 llvm::all_of(this->getOperandTypes(), checkType));
6271SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
6272DPICallIntrinsicOp::computeDataFlow() {
6276 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
6278 for (
auto operand : getOperands()) {
6279 auto type = type_cast<FIRRTLBaseType>(operand.getType());
6281 SmallVector<circt::FieldRef> operandFields;
6284 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
6288 for (
auto result : getResults())
6291 for (
auto field : operandFields)
6292 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
6302LogicalResult HWStructCastOp::verify() {
6304 BundleType bundleType;
6305 hw::StructType structType;
6306 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
6307 structType = dyn_cast<hw::StructType>(getType());
6309 return emitError(
"result type must be a struct");
6310 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
6311 structType = dyn_cast<hw::StructType>(getOperand().getType());
6313 return emitError(
"operand type must be a struct");
6315 return emitError(
"either source or result type must be a bundle type");
6318 auto firFields = bundleType.getElements();
6319 auto hwFields = structType.getElements();
6320 if (firFields.size() != hwFields.size())
6321 return emitError(
"bundle and struct have different number of fields");
6323 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6324 if (firFields[findex].name.getValue() != hwFields[findex].name)
6325 return emitError(
"field names don't match '")
6326 << firFields[findex].name.getValue() <<
"', '"
6327 << hwFields[findex].name.getValue() <<
"'";
6331 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6332 return emitError(
"size of field '")
6333 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6340LogicalResult BitCastOp::verify() {
6341 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6343 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6345 if (*inTypeBits == *resTypeBits) {
6348 return emitError(
"cannot cast non-'const' input type ")
6349 << getOperand().getType() <<
" to 'const' result type "
6353 return emitError(
"the bitwidth of input (")
6354 << *inTypeBits <<
") and result (" << *resTypeBits
6357 if (!inTypeBits.has_value())
6358 return emitError(
"bitwidth cannot be determined for input operand type ")
6359 << getInput().getType();
6360 return emitError(
"bitwidth cannot be determined for result type ")
6371 NamedAttrList &resultAttrs) {
6372 auto result = parser.parseOptionalAttrDict(resultAttrs);
6373 if (!resultAttrs.get(
"annotations"))
6374 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6380 DictionaryAttr attr,
6381 ArrayRef<StringRef> extraElides = {}) {
6382 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6384 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6385 elidedAttrs.push_back(
"annotations");
6387 elidedAttrs.push_back(
"nameKind");
6389 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6395 NamedAttrList &resultAttrs) {
6398 if (!resultAttrs.get(
"portAnnotations")) {
6399 SmallVector<Attribute, 16> portAnnotations(
6400 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6401 resultAttrs.append(
"portAnnotations",
6402 parser.getBuilder().getArrayAttr(portAnnotations));
6409 DictionaryAttr attr,
6410 ArrayRef<StringRef> extraElides = {}) {
6411 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6413 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6414 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6415 elidedAttrs.push_back(
"portAnnotations");
6424 firrtl::NameKindEnumAttr &result) {
6427 if (!parser.parseOptionalKeyword(&keyword,
6428 {
"interesting_name",
"droppable_name"})) {
6429 auto kind = symbolizeNameKindEnum(keyword);
6430 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6436 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6441 firrtl::NameKindEnumAttr attr,
6442 ArrayRef<StringRef> extraElides = {}) {
6443 if (attr.getValue() != NameKindEnum::DroppableName)
6444 p <<
" " << stringifyNameKindEnum(attr.getValue());
6452 NamedAttrList &resultAttrs) {
6460 DictionaryAttr attrs) {
6461 SmallVector<StringRef, 4> elides;
6463 elides.push_back(Forceable::getForceableAttrName());
6473 OpAsmParser &parser,
6474 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &fieldValues,
6475 SmallVectorImpl<Type> &fieldTypes, Type &resultType) {
6477 if (parser.parseType(resultType))
6480 auto domainType = dyn_cast<DomainType>(resultType);
6482 return parser.emitError(parser.getCurrentLocation(),
6483 "expected domain type");
6486 auto fields = domainType.getFields();
6489 if (fieldValues.size() != fields.size())
6490 return parser.emitError(parser.getCurrentLocation(),
6491 "number of field values (" +
6492 Twine(fieldValues.size()) +
6493 ") does not match domain field count (" +
6494 Twine(fields.size()) +
")");
6497 fieldTypes.reserve(fields.size());
6498 for (
auto field : fields)
6499 fieldTypes.push_back(cast<DomainFieldAttr>(field).getType());
6505 OperandRange fieldValues,
6506 TypeRange fieldTypes, Type resultType) {
6514static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6519static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6530 if (ClassType::parseInterface(parser, type))
6537 type.printInterface(p);
6545 NamedAttrList &resultAttrs) {
6546 auto result = p.parseOptionalAttrDict(resultAttrs);
6547 if (!resultAttrs.get(
"name"))
6548 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6554 DictionaryAttr attr,
6555 ArrayRef<StringRef> extraElides = {}) {
6556 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6557 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6558 elides.push_back(
"name");
6560 p.printOptionalAttrDict(op->getAttrs(), elides);
6564 NamedAttrList &resultAttrs) {
6569 DictionaryAttr attr) {
6574 NamedAttrList &resultAttrs) {
6579 DictionaryAttr attr) {
6581 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6589 DictionaryAttr attr) {
6598 DictionaryAttr attr) {
6607 OpAsmSetValueNameFn setNameFn) {
6610 if (op->getNumResults() == 1)
6611 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6612 setNameFn(op->getResult(0), nameAttr.getValue());
6615void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6619void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6623void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6627void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6630void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6633void AsResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6636void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6639void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6642void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6645void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6648void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6651void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6654void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6657void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6660void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6663void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6666void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6669void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6672void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6675void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6678void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6681void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6684void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6687void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6690void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6693void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6696void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6699void PlusArgsValueIntrinsicOp::getAsmResultNames(
6700 OpAsmSetValueNameFn setNameFn) {
6703void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6706void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6709void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6712void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6715void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6718void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6721void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6724void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6727void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6730void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6733void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6736void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6739void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6742void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6745void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6748void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6751void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6755void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6759void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6763void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6767void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6771void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6775void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6779void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6783void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6787void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6791void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6795void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6799void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6803void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6807void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6811void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6815void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6823void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6827void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6831void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6835void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6839void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6843FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6844 DictionaryAttr attrs,
6845 PropertyRef properties,
6846 mlir::RegionRange regions,
6847 std::optional<Location> loc) {
6848 Type inType = operands[0].getType();
6849 auto inRefType = type_dyn_cast<RefType>(inType);
6852 loc,
"ref.resolve operand must be ref type, not ", inType);
6853 return inRefType.getType();
6856FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6857 PropertyRef properties,
6858 mlir::RegionRange regions,
6859 std::optional<Location> loc) {
6860 Type inType = operands[0].getType();
6861 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6864 loc,
"ref.send operand must be base type, not ", inType);
6865 return RefType::get(inBaseType.getPassiveType());
6868FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6869 std::optional<Location> loc) {
6870 auto refType = type_dyn_cast<RefType>(type);
6873 auto inType = refType.getType();
6879 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6880 if (fieldIndex < vectorType.getNumElements())
6881 return RefType::get(
6882 vectorType.getElementType().getConstType(
6883 vectorType.isConst() || vectorType.getElementType().isConst()),
6884 refType.getForceable(), refType.getLayer());
6886 "' in RefType of vector type ", refType);
6888 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6889 if (fieldIndex >= bundleType.getNumElements()) {
6891 "subfield element index is greater than "
6892 "the number of fields in the bundle type");
6894 return RefType::get(
6895 bundleType.getElement(fieldIndex)
6897 bundleType.isConst() ||
6898 bundleType.getElement(fieldIndex).type.isConst()),
6899 refType.getForceable(), refType.getLayer());
6903 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6906LogicalResult RefCastOp::verify() {
6910 getOperation(), srcLayers, dstLayers,
6911 "cannot discard layer requirements of input reference",
6912 "discarding layer requirements");
6915LogicalResult RefResolveOp::verify() {
6919 getOperation(), srcLayers, dstLayers,
6920 "ambient layers are insufficient to resolve reference");
6924 auto targetRef = getTarget();
6925 if (targetRef.getModule() !=
6926 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6927 return emitOpError() <<
"has non-local target";
6929 auto target = ns.
lookup(targetRef);
6931 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6933 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6938 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6939 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6940 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6941 << fType <<
" instead of expected " << getType().getType();
6942 diag.attachNote(loc) <<
"target resolves here";
6947 if (target.isPort()) {
6948 auto mod = cast<FModuleLike>(target.getOp());
6949 return checkFinalType(mod.getPortType(target.getPort()),
6950 mod.getPortLocation(target.getPort()));
6952 hw::InnerSymbolOpInterface symOp =
6953 cast<hw::InnerSymbolOpInterface>(target.getOp());
6954 if (!symOp.getTargetResult())
6955 return emitOpError(
"has target that cannot be probed")
6956 .attachNote(symOp.getLoc())
6957 .append(
"target resolves here");
6959 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6960 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6961 return emitOpError(
"is not dominated by target")
6962 .attachNote(symOp.getLoc())
6963 .append(
"target here");
6964 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6967LogicalResult RefForceOp::verify() {
6971 getOperation(), destLayers, ambientLayers,
6972 "has insufficient ambient layers to force its reference");
6975LogicalResult RefForceInitialOp::verify() {
6979 getOperation(), destLayers, ambientLayers,
6980 "has insufficient ambient layers to force its reference");
6983LogicalResult RefReleaseOp::verify() {
6987 getOperation(), destLayers, ambientLayers,
6988 "has insufficient ambient layers to release its reference");
6991LogicalResult RefReleaseInitialOp::verify() {
6995 getOperation(), destLayers, ambientLayers,
6996 "has insufficient ambient layers to release its reference");
6999LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7000 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7002 return emitOpError(
"has an invalid symbol reference");
7004 if (!isa<hw::HierPathOp>(target))
7005 return emitOpError(
"does not target a hierpath op");
7011LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7012 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
7014 return emitOpError(
"has an invalid symbol reference");
7016 if (!isa<hw::HierPathOp>(target))
7017 return emitOpError(
"does not target a hierpath op");
7027LogicalResult LayerBlockOp::verify() {
7028 auto layerName = getLayerName();
7029 auto *parentOp = (*this)->getParentOp();
7032 while (isa<WhenOp, MatchOp>(parentOp))
7033 parentOp = parentOp->getParentOp();
7037 auto nestedReferences = layerName.getNestedReferences();
7038 if (nestedReferences.empty()) {
7039 if (!isa<FModuleOp>(parentOp)) {
7040 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
7041 "not have a 'firrtl.module' op as a parent";
7042 return diag.attachNote(parentOp->getLoc())
7043 <<
"illegal parent op defined here";
7046 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
7047 if (!parentLayerBlock) {
7048 auto diag = emitOpError()
7049 <<
"has a nested layer symbol, but does not have a '"
7050 << getOperationName() <<
"' op as a parent'";
7051 return diag.attachNote(parentOp->getLoc())
7052 <<
"illegal parent op defined here";
7054 auto parentLayerBlockName = parentLayerBlock.getLayerName();
7055 if (parentLayerBlockName.getRootReference() !=
7056 layerName.getRootReference() ||
7057 parentLayerBlockName.getNestedReferences() !=
7058 layerName.getNestedReferences().drop_back()) {
7059 auto diag = emitOpError() <<
"is nested under an illegal layer block";
7060 return diag.attachNote(parentLayerBlock->getLoc())
7061 <<
"illegal parent layer block defined here";
7067 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
7068 [&](Operation *op) -> WalkResult {
7070 if (isa<LayerBlockOp>(op))
7071 return WalkResult::skip();
7075 for (
auto operand : op->getOperands()) {
7077 if (
auto *definingOp = operand.getDefiningOp())
7081 auto type = operand.getType();
7084 if (isa<PropertyType>(type)) {
7085 auto diag = emitOpError() <<
"captures a property operand";
7086 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
7087 diag.attachNote(op->getLoc()) <<
"operand is used here";
7088 return WalkResult::interrupt();
7093 if (
auto connect = dyn_cast<FConnectLike>(op)) {
7095 if (isa<RefDefineOp>(connect))
7096 return WalkResult::advance();
7103 bool passive =
true;
7105 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
7106 passive = type.isPassive();
7115 return WalkResult::advance();
7118 return WalkResult::advance();
7122 <<
"connects to a destination which is defined outside its "
7123 "enclosing layer block";
7124 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
7125 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
7126 return WalkResult::interrupt();
7129 return WalkResult::advance();
7132 return failure(result.wasInterrupted());
7136LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7138 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
7140 return emitOpError(
"invalid symbol reference");
7150void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7151 setNameFn(getResult(),
"time");
7154void HierarchicalModuleNameOp::getAsmResultNames(
7155 OpAsmSetValueNameFn setNameFn) {
7156 setNameFn(getResult(),
"hierarchicalmodulename");
7159ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
7160 ::mlir::OperationState &result) {
7162 OpAsmParser::UnresolvedOperand clock, cond;
7163 if (parser.parseOperand(clock) || parser.parseComma() ||
7164 parser.parseOperand(cond) || parser.parseComma())
7168 [&parser](llvm::SMLoc &loc, StringAttr &result,
7169 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
7171 loc = parser.getCurrentLocation();
7174 std::string resultStr;
7175 if (parser.parseString(&resultStr))
7177 result = parser.getBuilder().getStringAttr(resultStr);
7180 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
7186 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
7188 llvm::SMLoc outputFileLoc, formatStringLoc;
7192 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
7193 outputFileSubstitutions) ||
7194 parser.parseComma() ||
7197 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
7205 Type clockType, condType;
7206 SmallVector<Type> restTypes;
7208 if (parser.parseColon() || parser.parseType(clockType) ||
7209 parser.parseComma() || parser.parseType(condType))
7212 if (succeeded(parser.parseOptionalComma())) {
7213 if (parser.parseTypeList(restTypes))
7218 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
7219 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
7220 static_cast<int32_t
>(substitutions.size())};
7223 if (parser.resolveOperand(clock, clockType, result.operands) ||
7224 parser.resolveOperand(cond, condType, result.operands) ||
7225 parser.resolveOperands(
7226 outputFileSubstitutions,
7227 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
7228 outputFileLoc, result.operands) ||
7229 parser.resolveOperands(
7231 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
7232 formatStringLoc, result.operands))
7238void FPrintFOp::print(OpAsmPrinter &p) {
7239 p <<
" " << getClock() <<
", " << getCond() <<
", ";
7240 p.printAttributeWithoutType(getOutputFileAttr());
7241 if (!getOutputFileSubstitutions().
empty()) {
7243 p.printOperands(getOutputFileSubstitutions());
7247 p.printAttributeWithoutType(getFormatStringAttr());
7248 if (!getSubstitutions().
empty()) {
7250 p.printOperands(getSubstitutions());
7254 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
7255 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
7256 for (
auto type : getOperands().drop_front(2).getTypes()) {
7267LogicalResult FFlushOp::verify() {
7268 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
7269 return emitOpError(
"substitutions without output file are not allowed");
7278 auto ref = getInstanceAttr();
7279 auto target = ns.
lookup(ref);
7281 return emitError() <<
"target " << ref <<
" cannot be resolved";
7283 if (!target.isOpOnly())
7284 return emitError() <<
"target " << ref <<
" is not an operation";
7286 auto instance = dyn_cast<InstanceOp>(target.getOp());
7288 return emitError() <<
"target " << ref <<
" is not an instance";
7290 if (!instance.getDoNotPrint())
7291 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
7300void DomainCreateAnonOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7305DomainCreateAnonOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7306 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7307 auto domainAttr = getDomainAttr();
7309 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7311 return emitOpError() <<
"references undefined symbol '" << domainAttr
7314 if (!isa<DomainOp>(symbol))
7315 return emitOpError() <<
"references symbol '" << domainAttr
7316 <<
"' which is not a domain";
7319 auto domainType = getResult().getType();
7320 return domainType.verifySymbolUses(getOperation(), symbolTable);
7323void DomainCreateOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
7328DomainCreateOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
7329 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
7330 auto domainAttr = getDomainAttr();
7332 auto *symbol = symbolTable.lookupSymbolIn(circuitOp, domainAttr);
7334 return emitOpError() <<
"references undefined symbol '" << domainAttr
7337 if (!isa<DomainOp>(symbol))
7338 return emitOpError() <<
"references symbol '" << domainAttr
7339 <<
"' which is not a domain";
7342 auto domainType = getResult().getType();
7343 return domainType.verifySymbolUses(getOperation(), symbolTable);
7346LogicalResult DomainCreateOp::verify() {
7348 auto domainType = getResult().getType();
7349 auto fields = domainType.getFields();
7350 auto fieldValues = getFieldValues();
7353 if (fieldValues.size() != fields.size())
7354 return emitOpError() <<
"has " << fieldValues.size()
7355 <<
" field value(s) but domain '"
7356 << domainType.getName() <<
"' expects "
7357 << fields.size() <<
" field(s)";
7360 for (
size_t i = 0; i < fields.size(); ++i) {
7361 auto fieldAttr = cast<DomainFieldAttr>(fields[i]);
7362 auto expectedType = fieldAttr.getType();
7363 auto actualType = fieldValues[i].getType();
7365 if (expectedType == actualType)
7368 return emitOpError() <<
"field value " << i <<
" has type " << actualType
7369 <<
" but domain field '" << fieldAttr.getName()
7370 <<
"' expects type " << expectedType;
7380StringAttr DomainSubfieldOp::getFieldName() {
7381 auto domainType = getInput().getType();
7382 auto fields = domainType.getFields();
7383 auto index = getFieldIndex();
7385 if (index >= fields.size())
7388 return cast<DomainFieldAttr>(fields[index]).getName();
7391Type DomainSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
7392 std::optional<Location> loc) {
7393 auto domainType = dyn_cast<DomainType>(inType);
7397 auto fields = domainType.getFields();
7398 if (fieldIndex >= fields.size())
7400 loc,
"field index ", fieldIndex,
7401 +
" is greater than the number of fields in the domain");
7403 return cast<DomainFieldAttr>(fields[fieldIndex]).getType();
7406Type DomainSubfieldOp::inferReturnType(ValueRange operands,
7407 mlir::DictionaryAttr attrs,
7408 mlir::PropertyRef properties,
7409 mlir::RegionRange regions,
7410 std::optional<Location> loc) {
7411 Adaptor adaptor(operands, attrs, properties, regions);
7412 return inferReturnType(adaptor.getInput().getType(), adaptor.getFieldIndex(),
7416DomainSubfieldOp DomainSubfieldOp::create(OpBuilder &builder, Type resultType,
7417 Value base,
unsigned fieldIndex) {
7418 OperationState state(builder.getUnknownLoc(),
7419 DomainSubfieldOp::getOperationName());
7420 state.addOperands(base);
7421 state.addAttribute(
"fieldIndex", builder.getI32IntegerAttr(fieldIndex));
7422 state.addTypes(resultType);
7423 return cast<DomainSubfieldOp>(builder.create(state));
7426LogicalResult DomainSubfieldOp::inferReturnTypes(
7427 MLIRContext *
context, std::optional<Location> location, ValueRange operands,
7428 DictionaryAttr attributes, PropertyRef properties, RegionRange regions,
7429 SmallVectorImpl<Type> &inferredReturnTypes) {
7430 Adaptor adaptor(operands, attributes, properties, regions);
7431 auto resultType = inferReturnType(adaptor.getInput().getType(),
7432 adaptor.getFieldIndex(), location);
7435 inferredReturnTypes.push_back(resultType);
7439void DomainSubfieldOp::print(OpAsmPrinter &p) {
7440 p <<
' ' << getInput() <<
"[";
7443 p.printOptionalAttrDict((*this)->getAttrs(), {
"fieldIndex"});
7444 p <<
" : " << getInput().getType();
7447ParseResult DomainSubfieldOp::parse(OpAsmParser &parser,
7448 OperationState &result) {
7449 auto *
context = parser.getContext();
7451 OpAsmParser::UnresolvedOperand input;
7452 std::string fieldName;
7453 DomainType inputType;
7455 if (parser.parseOperand(input) || parser.parseLSquare() ||
7456 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
7457 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
7458 parser.parseType(inputType) ||
7459 parser.resolveOperand(input, inputType, result.operands))
7463 auto fieldIndex = inputType.getFieldIndex(fieldName);
7465 return parser.emitError(parser.getNameLoc(),
7466 "unknown field '" + fieldName +
"' in domain type");
7469 result.addAttribute(
7471 IntegerAttr::get(IntegerType::get(
context, 32), *fieldIndex));
7474 auto resultType = inferReturnType(inputType, *fieldIndex, std::nullopt);
7478 result.addTypes(resultType);
7487#define GET_OP_CLASSES
7488#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 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.
int main(int argc, char **argv)
connect(destination, source)
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
SmallSet< SymbolRefAttr, 4, LayerSetCompare > LayerSet
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
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.