24 #include "mlir/IR/BuiltinTypes.h"
25 #include "mlir/IR/Diagnostics.h"
26 #include "mlir/IR/DialectImplementation.h"
27 #include "mlir/IR/PatternMatch.h"
28 #include "mlir/IR/SymbolTable.h"
29 #include "mlir/Interfaces/FunctionImplementation.h"
30 #include "llvm/ADT/BitVector.h"
31 #include "llvm/ADT/DenseMap.h"
32 #include "llvm/ADT/DenseSet.h"
33 #include "llvm/ADT/STLExtras.h"
34 #include "llvm/ADT/SmallSet.h"
35 #include "llvm/ADT/StringExtras.h"
36 #include "llvm/ADT/TypeSwitch.h"
37 #include "llvm/Support/FormatVariadic.h"
39 using llvm::SmallDenseSet;
40 using mlir::RegionRange;
41 using namespace circt;
42 using namespace firrtl;
43 using namespace chirrtl;
54 const llvm::BitVector &indicesToDrop) {
57 int lastIndex = indicesToDrop.find_last();
59 assert((
size_t)lastIndex < input.size() &&
"index out of range");
69 size_t lastCopied = 0;
70 SmallVector<T> result;
71 result.reserve(input.size() - indicesToDrop.count());
73 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
75 if (indexToDrop > lastCopied) {
76 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
77 lastCopied = indexToDrop;
84 if (lastCopied < input.size())
85 result.append(input.begin() + lastCopied, input.end());
91 template <
typename RetTy =
FIRRTLType,
typename... Args>
93 const Twine &message, Args &&...args) {
95 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
101 while (Operation *op = val.getDefiningOp()) {
103 TypeSwitch<Operation *, std::optional<bool>>(op)
104 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
108 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
109 .Default([](
auto) {
return false; });
118 constexpr
unsigned int addr = 1 << 0;
119 constexpr
unsigned int en = 1 << 1;
120 constexpr
unsigned int clk = 1 << 2;
121 constexpr
unsigned int data = 1 << 3;
122 constexpr
unsigned int mask = 1 << 4;
123 constexpr
unsigned int rdata = 1 << 5;
124 constexpr
unsigned int wdata = 1 << 6;
125 constexpr
unsigned int wmask = 1 << 7;
126 constexpr
unsigned int wmode = 1 << 8;
127 constexpr
unsigned int def = 1 << 9;
129 auto portType = type_dyn_cast<BundleType>(type);
131 return MemOp::PortKind::Debug;
134 for (
auto elem : portType.getElements()) {
135 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
141 .Case(
"rdata",
rdata)
142 .Case(
"wdata",
wdata)
143 .Case(
"wmask",
wmask)
144 .Case(
"wmode",
wmode)
148 return MemOp::PortKind::Read;
150 return MemOp::PortKind::Write;
152 return MemOp::PortKind::ReadWrite;
153 return MemOp::PortKind::Debug;
174 return "source flow";
178 return "duplex flow";
184 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
185 auto *op = val.getParentBlock()->getParentOp();
186 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
187 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
191 return accumulatedFlow;
194 Operation *op = val.getDefiningOp();
196 return TypeSwitch<Operation *, Flow>(op)
197 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
198 return foldFlow(op.getInput(), op.isFieldFlipped()
202 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
203 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
205 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
207 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
208 auto resultNo = cast<OpResult>(val).getResultNumber();
210 return accumulatedFlow;
213 .Case<MemOp>([&](
auto op) {
215 if (type_isa<RefType>(val.getType()))
219 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
220 auto input = op.getInput();
221 auto *inputOp = input.getDefiningOp();
224 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
225 auto classType = input.getType();
226 auto direction = classType.getElement(op.getIndex()).direction;
238 auto classType = input.getType();
239 auto direction = classType.getElement(op.getIndex()).direction;
243 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
245 input = op.getInput();
246 inputOp = input.getDefiningOp();
250 return accumulatedFlow;
254 .Default([&](
auto) {
return accumulatedFlow; });
260 Operation *op = val.getDefiningOp();
264 return TypeSwitch<Operation *, DeclKind>(op)
266 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
272 if (
auto module = dyn_cast<FModuleLike>(op))
273 return module.getNumPorts();
274 return op->getNumResults();
288 if (
auto *op = value.getDefiningOp())
290 auto arg = dyn_cast<BlockArgument>(value);
291 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
292 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
303 auto *block = ®ion.front();
306 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
308 if (!argAttr || argAttr.size() != block->getNumArguments())
311 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
312 auto str = cast<StringAttr>(argAttr[i]).getValue();
314 setNameFn(block->getArgument(i), str);
320 firrtl::NameKindEnumAttr &result);
327 struct CompareSymbolRefAttr {
329 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
330 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
335 auto lhsNested = lhs.getNestedReferences();
336 auto rhsNested = rhs.getNestedReferences();
337 auto lhsNestedSize = lhsNested.size();
338 auto rhsNestedSize = rhsNested.size();
339 auto e = std::min(lhsNestedSize, rhsNestedSize);
340 for (
unsigned i = 0; i < e; ++i) {
341 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].
getAttr());
347 return lhsNestedSize < rhsNestedSize;
359 for (; op !=
nullptr; op = op->getParentOp()) {
360 if (
auto module = dyn_cast<FModuleLike>(op)) {
361 auto layers = module.getLayersAttr().getAsRange<SymbolRefAttr>();
362 result.insert(layers.begin(), layers.end());
365 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
366 result.insert(layerblock.getLayerName());
384 if (
auto type = dyn_cast<RefType>(value.getType()))
385 if (
auto layer = type.getLayer())
386 result.insert(type.getLayer());
395 mlir::SymbolRefAttr dstLayer) {
405 if (srcLayer.getRootReference() != dstLayer.getRootReference())
408 auto srcNames = srcLayer.getNestedReferences();
409 auto dstNames = dstLayer.getNestedReferences();
410 if (dstNames.size() < srcNames.size())
413 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
414 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
421 if (dstLayers.contains(srcLayer))
426 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
435 SmallVectorImpl<SymbolRefAttr> &missing) {
436 for (
auto srcLayer : src)
438 missing.push_back(srcLayer);
440 llvm::sort(missing, CompareSymbolRefAttr());
441 return missing.empty();
448 void CircuitOp::build(OpBuilder &
builder, OperationState &result,
449 StringAttr name, ArrayAttr annotations) {
451 result.addAttribute(
builder.getStringAttr(
"name"), name);
454 annotations =
builder.getArrayAttr({});
455 result.addAttribute(
"annotations", annotations);
458 Region *bodyRegion = result.addRegion();
460 bodyRegion->push_back(body);
464 NamedAttrList &resultAttrs) {
465 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
466 if (!resultAttrs.get(
"annotations"))
467 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
473 DictionaryAttr attr) {
475 SmallVector<StringRef> elidedAttrs = {
"name"};
477 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
478 if (annotationsAttr.empty())
479 elidedAttrs.push_back(
"annotations");
481 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
484 LogicalResult CircuitOp::verifyRegions() {
489 emitOpError(
"must have a non-empty name");
493 mlir::SymbolTable symtbl(getOperation());
495 if (!symtbl.lookup(
main))
496 return emitOpError().append(
"Module with same name as circuit not found");
501 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
503 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
507 auto defname = extModule.getDefnameAttr();
513 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
514 return extModule.emitOpError()
515 .append(
"attribute 'defname' with value ", defname,
516 " conflicts with the name of another module in the circuit")
517 .attachNote(collidingModule.getLoc())
518 .append(
"previous module declared here");
526 FExtModuleOp collidingExtModule;
527 if (
auto &value = defnameMap[defname]) {
528 collidingExtModule = value;
529 if (!value.getParameters().empty() && extModule.getParameters().empty())
539 SmallVector<PortInfo> ports = extModule.getPorts();
540 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
542 if (ports.size() != collidingPorts.size())
543 return extModule.emitOpError()
544 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
545 " ports which is different from a previously defined "
546 "extmodule with the same 'defname' which has ",
547 collidingPorts.size(),
" ports")
548 .attachNote(collidingExtModule.getLoc())
549 .append(
"previous extmodule definition occurred here");
555 for (
auto p : llvm::zip(ports, collidingPorts)) {
556 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
557 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
560 return extModule.emitOpError()
561 .append(
"with 'defname' attribute ", defname,
562 " has a port with name ", aName,
563 " which does not match the name of the port in the same "
564 "position of a previously defined extmodule with the same "
565 "'defname', expected port to have name ",
567 .attachNote(collidingExtModule.getLoc())
568 .append(
"previous extmodule definition occurred here");
570 if (!extModule.getParameters().empty() ||
571 !collidingExtModule.getParameters().empty()) {
573 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
574 aType = base.getWidthlessType();
575 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
576 bType = base.getWidthlessType();
579 return extModule.emitOpError()
580 .append(
"with 'defname' attribute ", defname,
581 " has a port with name ", aName,
582 " which has a different type ", aType,
583 " which does not match the type of the port in the same "
584 "position of a previously defined extmodule with the same "
585 "'defname', expected port to have type ",
587 .attachNote(collidingExtModule.getLoc())
588 .append(
"previous extmodule definition occurred here");
593 for (
auto &op : *getBodyBlock()) {
595 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
596 if (verifyExtModule(extModule).failed())
604 Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
611 SmallVector<PortInfo> results;
612 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
613 results.push_back({module.getPortNameAttr(i), module.getPortType(i),
614 module.getPortDirection(i), module.getPortSymbolAttr(i),
615 module.getPortLocation(i),
634 assert(0 &&
"invalid direction");
639 SmallVector<hw::PortInfo> results;
641 hw::HWModuleLike::getPortSymbolAttrName());
643 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
644 auto sym = module.getPortSymbolAttr(i);
646 {{module.getPortNameAttr(i), module.getPortType(i),
647 dirFtoH(module.getPortDirection(i))},
651 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
653 module.getPortLocation(i)});
675 return {{module.getPortNameAttr(idx), module.getPortType(idx),
676 dirFtoH(module.getPortDirection(idx))},
680 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
681 StringAttr::get(module.getContext(),
682 hw::HWModuleLike::getPortSymbolAttrName()),
683 module.getPortSymbolAttr(idx)}}),
684 module.getPortLocation(idx)};
704 BlockArgument FModuleOp::getArgument(
size_t portNumber) {
705 return getBodyBlock()->getArgument(portNumber);
712 ArrayRef<std::pair<unsigned, PortInfo>> ports,
713 bool supportsInternalPaths =
false) {
716 unsigned oldNumArgs = op.getNumPorts();
717 unsigned newNumArgs = oldNumArgs + ports.size();
720 auto existingDirections = op.getPortDirectionsAttr();
721 ArrayRef<Attribute> existingNames = op.getPortNames();
722 ArrayRef<Attribute> existingTypes = op.getPortTypes();
723 ArrayRef<Attribute> existingLocs = op.getPortLocations();
724 assert(existingDirections.size() == oldNumArgs);
725 assert(existingNames.size() == oldNumArgs);
726 assert(existingTypes.size() == oldNumArgs);
727 assert(existingLocs.size() == oldNumArgs);
728 SmallVector<Attribute> internalPaths;
730 if (supportsInternalPaths) {
731 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
732 llvm::append_range(internalPaths, internalPathsAttr);
734 internalPaths.resize(oldNumArgs, emptyInternalPath);
735 assert(internalPaths.size() == oldNumArgs);
738 SmallVector<bool> newDirections;
739 SmallVector<Attribute> newNames, newTypes, newAnnos, newSyms, newLocs,
741 newDirections.reserve(newNumArgs);
742 newNames.reserve(newNumArgs);
743 newTypes.reserve(newNumArgs);
744 newAnnos.reserve(newNumArgs);
745 newSyms.reserve(newNumArgs);
746 newLocs.reserve(newNumArgs);
747 newInternalPaths.reserve(newNumArgs);
752 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
753 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
754 newDirections.push_back(existingDirections[oldIdx]);
755 newNames.push_back(existingNames[oldIdx]);
756 newTypes.push_back(existingTypes[oldIdx]);
757 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
758 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
759 newLocs.push_back(existingLocs[oldIdx]);
760 if (supportsInternalPaths)
761 newInternalPaths.push_back(internalPaths[oldIdx]);
765 for (
auto pair : llvm::enumerate(ports)) {
766 auto idx = pair.value().first;
767 auto &port = pair.value().second;
768 migrateOldPorts(idx);
770 newNames.push_back(port.name);
772 auto annos = port.annotations.getArrayAttr();
773 newAnnos.push_back(annos ? annos : emptyArray);
774 newSyms.push_back(port.sym);
775 newLocs.push_back(port.loc);
776 if (supportsInternalPaths)
777 newInternalPaths.push_back(emptyInternalPath);
779 migrateOldPorts(oldNumArgs);
783 if (llvm::all_of(newAnnos, [](Attribute attr) {
784 return cast<ArrayAttr>(attr).empty();
789 op->setAttr(
"portDirections",
791 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newNames));
792 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newTypes));
793 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newAnnos));
794 op.setPortSymbols(newSyms);
795 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newLocs));
796 if (supportsInternalPaths) {
798 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
799 return !cast<InternalPathAttr>(attr).getPath();
802 op->removeAttr(
"internalPaths");
804 op->setAttr(
"internalPaths",
810 static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
811 if (portIndices.none())
815 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
816 ArrayRef<Attribute> portNames = op.getPortNames();
817 ArrayRef<Attribute> portTypes = op.getPortTypes();
818 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
819 ArrayRef<Attribute> portSyms = op.getPortSymbols();
820 ArrayRef<Attribute> portLocs = op.getPortLocations();
821 auto numPorts = op.getNumPorts();
823 assert(portDirections.size() == numPorts);
824 assert(portNames.size() == numPorts);
825 assert(portAnnos.size() == numPorts || portAnnos.empty());
826 assert(portTypes.size() == numPorts);
827 assert(portSyms.size() == numPorts || portSyms.empty());
828 assert(portLocs.size() == numPorts);
830 SmallVector<bool> newPortDirections =
831 removeElementsAtIndices<bool>(portDirections, portIndices);
832 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
839 op->setAttr(
"portDirections",
841 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newPortNames));
842 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newPortAnnos));
843 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newPortTypes));
844 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
845 op->setAttr(
"portSyms",
ArrayAttr::get(op.getContext(), newPortSyms));
846 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newPortLocs));
849 template <
typename T>
852 auto internalPaths = op.getInternalPaths();
860 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
861 return !cast<InternalPathAttr>(attr).getPath();
864 op.removeInternalPathsAttr();
866 op.setInternalPathsAttr(
ArrayAttr::get(op.getContext(), newPaths));
870 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
875 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
880 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
884 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
885 getBodyBlock()->eraseArguments(portIndices);
895 auto *body = getBodyBlock();
896 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
899 auto &[index, port] = ports[i];
900 body->insertArgument(index + i, port.type, port.loc);
922 StringAttr name, ArrayRef<PortInfo> ports,
923 ArrayAttr annotations, ArrayAttr layers,
924 bool withAnnotations,
bool withLayers) {
926 result.addAttribute(::mlir::SymbolTable::getSymbolAttrName(), name);
929 SmallVector<Direction, 4> portDirections;
930 SmallVector<Attribute, 4> portNames;
931 SmallVector<Attribute, 4> portTypes;
932 SmallVector<Attribute, 4> portAnnotations;
933 SmallVector<Attribute, 4> portSyms;
934 SmallVector<Attribute, 4> portLocs;
935 for (
const auto &port : ports) {
936 portDirections.push_back(port.direction);
937 portNames.push_back(port.name);
939 portAnnotations.push_back(port.annotations.getArrayAttr());
940 portSyms.push_back(port.sym);
941 portLocs.push_back(port.loc);
946 if (llvm::all_of(portAnnotations, [](Attribute attr) {
947 return cast<ArrayAttr>(attr).empty();
949 portAnnotations.clear();
951 FModuleLike::fixupPortSymsArray(portSyms,
builder.getContext());
956 result.addAttribute(
"portNames",
builder.getArrayAttr(portNames));
957 result.addAttribute(
"portTypes",
builder.getArrayAttr(portTypes));
958 result.addAttribute(
"portSyms",
builder.getArrayAttr(portSyms));
959 result.addAttribute(
"portLocations",
builder.getArrayAttr(portLocs));
961 if (withAnnotations) {
963 annotations =
builder.getArrayAttr({});
964 result.addAttribute(
"annotations", annotations);
965 result.addAttribute(
"portAnnotations",
966 builder.getArrayAttr(portAnnotations));
971 layers =
builder.getArrayAttr({});
972 result.addAttribute(
"layers", layers);
979 StringAttr name, ArrayRef<PortInfo> ports,
980 ArrayAttr annotations, ArrayAttr layers) {
986 StringAttr name, ArrayRef<PortInfo> ports) {
992 void FModuleOp::build(OpBuilder &
builder, OperationState &result,
993 StringAttr name, ConventionAttr convention,
994 ArrayRef<PortInfo> ports, ArrayAttr annotations,
997 result.addAttribute(
"convention", convention);
1000 auto *bodyRegion = result.regions[0].get();
1002 bodyRegion->push_back(body);
1005 for (
auto &elt : ports)
1006 body->addArgument(elt.type, elt.loc);
1009 void FExtModuleOp::build(OpBuilder &
builder, OperationState &result,
1010 StringAttr name, ConventionAttr convention,
1011 ArrayRef<PortInfo> ports, StringRef defnameAttr,
1012 ArrayAttr annotations, ArrayAttr parameters,
1013 ArrayAttr internalPaths, ArrayAttr layers) {
1015 result.addAttribute(
"convention", convention);
1016 if (!defnameAttr.empty())
1017 result.addAttribute(
"defname",
builder.getStringAttr(defnameAttr));
1019 parameters =
builder.getArrayAttr({});
1020 result.addAttribute(getParametersAttrName(result.name), parameters);
1021 if (internalPaths && !internalPaths.empty())
1022 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1025 void FIntModuleOp::build(OpBuilder &
builder, OperationState &result,
1026 StringAttr name, ArrayRef<PortInfo> ports,
1027 StringRef intrinsicNameStr, ArrayAttr annotations,
1028 ArrayAttr parameters, ArrayAttr internalPaths,
1031 result.addAttribute(
"intrinsic",
builder.getStringAttr(intrinsicNameStr));
1033 parameters =
builder.getArrayAttr({});
1034 result.addAttribute(getParametersAttrName(result.name), parameters);
1035 if (internalPaths && !internalPaths.empty())
1036 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1039 void FMemModuleOp::build(OpBuilder &
builder, OperationState &result,
1040 StringAttr name, ArrayRef<PortInfo> ports,
1041 uint32_t numReadPorts, uint32_t numWritePorts,
1042 uint32_t numReadWritePorts, uint32_t dataWidth,
1043 uint32_t maskBits, uint32_t readLatency,
1044 uint32_t writeLatency, uint64_t depth,
1045 ArrayAttr annotations, ArrayAttr layers) {
1046 auto *context =
builder.getContext();
1050 result.addAttribute(
"numReadPorts",
IntegerAttr::get(ui32Type, numReadPorts));
1051 result.addAttribute(
"numWritePorts",
1053 result.addAttribute(
"numReadWritePorts",
1057 result.addAttribute(
"readLatency",
IntegerAttr::get(ui32Type, readLatency));
1058 result.addAttribute(
"writeLatency",
IntegerAttr::get(ui32Type, writeLatency));
1077 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1078 ArrayRef<Attribute> portAnnotations,
1079 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs) {
1082 bool printedNamesDontMatch =
false;
1084 mlir::OpPrintingFlags flags;
1088 SmallString<32> resultNameStr;
1090 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1101 resultNameStr.clear();
1102 llvm::raw_svector_ostream tmpStream(resultNameStr);
1103 p.printOperand(block->getArgument(i), tmpStream);
1106 auto portName = cast<StringAttr>(portNames[i]).getValue();
1107 if (!portName.empty() && tmpStream.str().drop_front() != portName)
1108 printedNamesDontMatch =
true;
1109 p << tmpStream.str();
1111 p.printKeywordOrString(cast<StringAttr>(portNames[i]).getValue());
1116 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1117 p.printType(portType);
1120 if (!portSyms.empty()) {
1121 if (!portSyms[i].cast<hw::InnerSymAttr>().
empty()) {
1123 portSyms[i].cast<hw::InnerSymAttr>().print(p);
1129 if (!portAnnotations.empty() &&
1130 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1132 p.printAttribute(portAnnotations[i]);
1139 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1140 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1144 return printedNamesDontMatch;
1151 bool supportsSymbols,
1152 SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1153 SmallVectorImpl<Direction> &portDirections,
1154 SmallVectorImpl<Attribute> &portNames,
1155 SmallVectorImpl<Attribute> &portTypes,
1156 SmallVectorImpl<Attribute> &portAnnotations,
1157 SmallVectorImpl<Attribute> &portSyms,
1158 SmallVectorImpl<Attribute> &portLocs) {
1159 auto *context = parser.getContext();
1161 auto parseArgument = [&]() -> ParseResult {
1163 if (succeeded(parser.parseOptionalKeyword(
"out")))
1164 portDirections.push_back(Direction::Out);
1165 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
1166 portDirections.push_back(Direction::In);
1174 if (hasSSAIdentifiers) {
1175 OpAsmParser::Argument arg;
1176 if (parser.parseArgument(arg))
1178 entryArgs.push_back(arg);
1182 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1183 "Unknown MLIR name");
1184 if (
isdigit(arg.ssaName.name[1]))
1187 portNames.push_back(
1191 irLoc = arg.ssaName.location;
1195 irLoc = parser.getCurrentLocation();
1196 std::string portName;
1197 if (parser.parseKeywordOrString(&portName))
1204 if (parser.parseColonType(portType))
1208 if (hasSSAIdentifiers)
1209 entryArgs.back().type = portType;
1212 if (supportsSymbols) {
1213 hw::InnerSymAttr innerSymAttr;
1214 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1215 NamedAttrList dummyAttrs;
1216 if (parser.parseCustomAttributeWithFallback(
1217 innerSymAttr, ::mlir::Type{},
1219 return ::mlir::failure();
1222 portSyms.push_back(innerSymAttr);
1227 auto parseResult = parser.parseOptionalAttribute(annos);
1228 if (!parseResult.has_value())
1229 annos = parser.getBuilder().getArrayAttr({});
1230 else if (failed(*parseResult))
1232 portAnnotations.push_back(annos);
1235 std::optional<Location> maybeLoc;
1236 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1238 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1239 portLocs.push_back(loc);
1240 if (hasSSAIdentifiers)
1241 entryArgs.back().sourceLoc = loc;
1247 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1253 ArrayAttr parameters) {
1254 if (!parameters || parameters.empty())
1258 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1259 auto paramAttr = cast<ParamDeclAttr>(param);
1260 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1261 if (
auto value = paramAttr.getValue()) {
1263 p.printAttributeWithoutType(value);
1269 static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op) {
1272 // Print the visibility of the module.
1273 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1274 if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1275 p << visibility.getValue() << ' ';
1277 // Print the operation and the function name.
1278 p.printSymbolName(op.getModuleName());
1280 // Print the parameter list (if non-empty).
1281 printParameterList(p, op, op->getAttrOfType<ArrayAttr>("parameters"));
1283 // Both modules and external modules have a body, but it is always empty for
1284 // external modules.
1285 Block *body = nullptr;
1286 if (!op->getRegion(0).empty())
1287 body = &op->getRegion(0).front();
1289 auto needPortNamesAttr = printModulePorts(
1290 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1291 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations());
1293 SmallVector<StringRef, 12> omittedAttrs = {
1294 "sym_name", "portDirections", "portTypes", "portAnnotations",
1295 "portSyms", "portLocations", "parameters", visibilityAttrName};
1297 if (op.getConvention() == Convention::Internal)
1298 omittedAttrs.push_back("convention");
1300 // We can omit the portNames if they were able to be printed as properly as
1302 if (!needPortNamesAttr)
1303 omittedAttrs.push_back("portNames");
1305 // If there are no annotations we can omit the empty array.
1306 if (op->getAttrOfType<ArrayAttr>("annotations").empty())
1307 omittedAttrs.push_back("annotations");
1309 // If there are no enabled layers, then omit the empty array.
1310 if (auto layers = op->getAttrOfType<ArrayAttr>("layers"))
1312 omittedAttrs.push_back("layers");
1314 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1317 void FExtModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1319 void FIntModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1321 void FMemModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1323 void FModuleOp::print(OpAsmPrinter &p) {
1324 printFModuleLikeOp(p, *this);
1326 // Print the body if this is not an external function. Since this block does
1327 // not have terminators, printing the terminator actually just prints the last
1329 Region &fbody = getBody();
1330 if (!fbody.empty()) {
1332 p.printRegion(fbody, /*printEntryBlockArgs=*/false,
1333 /*printBlockTerminators=*/true);
1343 parseOptionalParameters(OpAsmParser &parser,
1344 SmallVectorImpl<Attribute> ¶meters) {
1346 return parser.parseCommaSeparatedList(
1347 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1352 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1355 // Parse the default value if present.
1356 if (succeeded(parser.parseOptionalEqual())) {
1357 if (parser.parseAttribute(value, type))
1361 auto &builder = parser.getBuilder();
1362 parameters.push_back(ParamDeclAttr::get(
1363 builder.getContext(), builder.getStringAttr(name), type, value));
1369 static ParseResult parseParameterList(OpAsmParser &parser,
1370 ArrayAttr ¶meters) {
1371 SmallVector<Attribute> parseParameters;
1372 if (failed(parseOptionalParameters(parser, parseParameters)))
1375 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1380 static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
1381 OperationState &result,
1382 bool hasSSAIdentifiers) {
1383 auto *context = result.getContext();
1384 auto &builder = parser.getBuilder();
1386 // Parse the visibility attribute.
1387 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1389 // Parse the name as a symbol.
1390 StringAttr nameAttr;
1391 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1395 // Parse optional parameters.
1396 SmallVector<Attribute, 4> parameters;
1397 if (parseOptionalParameters(parser, parameters))
1399 result.addAttribute("parameters", builder.getArrayAttr(parameters));
1401 // Parse the module ports.
1402 SmallVector<OpAsmParser::Argument> entryArgs;
1403 SmallVector<Direction, 4> portDirections;
1404 SmallVector<Attribute, 4> portNames;
1405 SmallVector<Attribute, 4> portTypes;
1406 SmallVector<Attribute, 4> portAnnotations;
1407 SmallVector<Attribute, 4> portSyms;
1408 SmallVector<Attribute, 4> portLocs;
1409 if (parseModulePorts(parser, hasSSAIdentifiers, /*supportsSymbols=*/true,
1410 entryArgs, portDirections, portNames, portTypes,
1411 portAnnotations, portSyms, portLocs))
1414 // If module attributes are present, parse them.
1415 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1418 assert(portNames.size() == portTypes.size());
1420 // Record the argument and result types as an attribute. This is necessary
1421 // for external modules.
1423 // Add port directions.
1424 if (!result.attributes.get("portDirections"))
1425 result.addAttribute("portDirections",
1426 direction::packAttribute(context, portDirections));
1429 if (!result.attributes.get("portNames"))
1430 result.addAttribute("portNames", builder.getArrayAttr(portNames));
1432 // Add the port types.
1433 if (!result.attributes.get("portTypes"))
1434 result.addAttribute("portTypes", ArrayAttr::get(context, portTypes));
1436 // Add the port annotations.
1437 if (!result.attributes.get("portAnnotations")) {
1438 // If there are no portAnnotations, don't add the attribute.
1439 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1440 return !cast<ArrayAttr>(anno).empty();
1442 result.addAttribute(
"portAnnotations",
1447 if (!result.attributes.get(
"portSyms")) {
1448 FModuleLike::fixupPortSymsArray(portSyms,
builder.getContext());
1449 result.addAttribute(
"portSyms",
builder.getArrayAttr(portSyms));
1453 if (!result.attributes.get(
"portLocations"))
1454 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1457 if (!result.attributes.get(
"annotations"))
1458 result.addAttribute(
"annotations",
builder.getArrayAttr({}));
1462 if (!result.attributes.get(
"portAnnotations"))
1463 result.addAttribute(
"portAnnotations",
builder.getArrayAttr({}));
1466 auto *body = result.addRegion();
1468 if (hasSSAIdentifiers) {
1469 if (parser.parseRegion(*body, entryArgs))
1472 body->push_back(
new Block());
1477 ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1480 if (!result.attributes.get(
"convention"))
1481 result.addAttribute(
1484 if (!result.attributes.get(
"layers"))
1485 result.addAttribute(
"layers",
ArrayAttr::get(parser.getContext(), {}));
1489 ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1492 if (!result.attributes.get(
"convention"))
1493 result.addAttribute(
1499 ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1503 ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1507 LogicalResult FModuleOp::verify() {
1509 auto *body = getBodyBlock();
1510 auto portTypes = getPortTypes();
1511 auto portLocs = getPortLocations();
1512 auto numPorts = portTypes.size();
1515 if (body->getNumArguments() != numPorts)
1516 return emitOpError(
"entry block must have ")
1517 << numPorts <<
" arguments to match module signature";
1520 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1521 if (arg.getType() != cast<TypeAttr>(type).getValue())
1522 return emitOpError(
"block argument types should match signature types");
1523 if (arg.getLoc() != cast<LocationAttr>(loc))
1525 "block argument locations should match signature locations");
1531 static LogicalResult
1533 std::optional<::mlir::ArrayAttr> internalPaths) {
1538 if (internalPaths->size() != op.getNumPorts())
1539 return op.emitError(
"module has inconsistent internal path array with ")
1540 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1544 for (
auto [idx, path, typeattr] : llvm::enumerate(
1545 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1546 if (path.getPath() &&
1547 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1549 op.emitError(
"module has internal path for non-ref-type port ")
1550 << op.getPortNameAttr(idx);
1551 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1558 LogicalResult FExtModuleOp::verify() {
1562 auto params = getParameters();
1566 auto checkParmValue = [&](Attribute elt) ->
bool {
1567 auto param = cast<ParamDeclAttr>(elt);
1568 auto value = param.getValue();
1569 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1571 emitError() <<
"has unknown extmodule parameter value '"
1572 << param.getName().getValue() <<
"' = " << value;
1576 if (!llvm::all_of(params, checkParmValue))
1582 LogicalResult FIntModuleOp::verify() {
1586 auto params = getParameters();
1590 auto checkParmValue = [&](Attribute elt) ->
bool {
1591 auto param = cast<ParamDeclAttr>(elt);
1592 auto value = param.getValue();
1593 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1595 emitError() <<
"has unknown intmodule parameter value '"
1596 << param.getName().getValue() <<
"' = " << value;
1600 if (!llvm::all_of(params, checkParmValue))
1607 CircuitOp circuitOp,
1608 SymbolTableCollection &symbolTable,
1610 auto layer = refType.getLayer();
1613 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1615 return emitError(loc) << start <<
" associated with layer '" << layer
1616 <<
"', but this layer was not defined";
1617 if (!isa<LayerOp>(layerOp)) {
1618 auto diag = emitError(loc)
1619 << start <<
" associated with layer '" << layer
1620 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1621 << LayerOp::getOperationName() <<
"' op";
1622 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1628 SymbolTableCollection &symbolTable) {
1630 auto circuitOp = module->getParentOfType<CircuitOp>();
1631 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1632 auto type = module.getPortType(i);
1634 if (
auto refType = type_dyn_cast<RefType>(type)) {
1636 refType, module.getPortLocation(i), circuitOp, symbolTable,
1637 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1642 if (
auto classType = dyn_cast<ClassType>(type)) {
1643 auto className = classType.getNameAttr();
1644 auto classOp = dyn_cast_or_null<ClassLike>(
1645 symbolTable.lookupSymbolIn(circuitOp, className));
1647 return module.emitOpError() <<
"references unknown class " << className;
1650 if (failed(classOp.verifyType(classType,
1651 [&]() { return module.emitOpError(); })))
1660 LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1665 auto circuitOp = (*this)->getParentOfType<CircuitOp>();
1666 for (
auto layer : getLayers()) {
1667 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1668 return emitOpError() <<
"enables unknown layer '" << layer <<
"'";
1675 FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1680 FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1685 FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1689 void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1694 void FExtModuleOp::getAsmBlockArgumentNames(
1699 void FIntModuleOp::getAsmBlockArgumentNames(
1704 void FMemModuleOp::getAsmBlockArgumentNames(
1709 ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1711 ArrayAttr FModuleOp::getParameters() {
return {}; }
1713 Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1715 ConventionAttr FIntModuleOp::getConventionAttr() {
1719 Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1721 ConventionAttr FMemModuleOp::getConventionAttr() {
1730 ClassLike classOp, ClassType type,
1731 function_ref<InFlightDiagnostic()> emitError) {
1733 auto name = type.getNameAttr().getAttr();
1734 auto expectedName = classOp.getModuleNameAttr();
1735 if (name != expectedName)
1736 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1739 auto elements = type.getElements();
1741 auto expectedNumElements = classOp.getNumPorts();
1743 return emitError() <<
"has wrong number of ports, got " <<
numElements
1744 <<
", expected " << expectedNumElements;
1746 auto portNames = classOp.getPortNames();
1747 auto portDirections = classOp.getPortDirections();
1748 auto portTypes = classOp.getPortTypes();
1751 auto element = elements[i];
1753 auto name = element.name;
1754 auto expectedName = portNames[i];
1755 if (name != expectedName)
1756 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
1757 <<
", expected " << expectedName;
1759 auto direction = element.direction;
1760 auto expectedDirection =
Direction(portDirections[i]);
1761 if (direction != expectedDirection)
1762 return emitError() <<
"port " << name <<
" has wrong direction, got "
1766 auto type = element.type;
1767 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
1768 if (type != expectedType)
1769 return emitError() <<
"port " << name <<
" has wrong type, got " << type
1770 <<
", expected " << expectedType;
1777 auto n = classOp.getNumPorts();
1778 SmallVector<ClassElement> elements;
1779 elements.reserve(n);
1780 for (
size_t i = 0; i < n; ++i)
1781 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
1782 classOp.getPortDirection(i)});
1788 bool hasSSAIdentifiers) {
1789 auto *context = result.getContext();
1790 auto &
builder = parser.getBuilder();
1793 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1796 StringAttr nameAttr;
1797 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1802 SmallVector<OpAsmParser::Argument> entryArgs;
1803 SmallVector<Direction, 4> portDirections;
1804 SmallVector<Attribute, 4> portNames;
1805 SmallVector<Attribute, 4> portTypes;
1806 SmallVector<Attribute, 4> portAnnotations;
1807 SmallVector<Attribute, 4> portSyms;
1808 SmallVector<Attribute, 4> portLocs;
1810 false, entryArgs, portDirections,
1811 portNames, portTypes, portAnnotations, portSyms,
1816 for (
auto annos : portAnnotations)
1817 if (!cast<ArrayAttr>(annos).empty())
1821 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1824 assert(portNames.size() == portTypes.size());
1830 if (!result.attributes.get(
"portDirections"))
1831 result.addAttribute(
"portDirections",
1835 if (!result.attributes.get(
"portNames"))
1836 result.addAttribute(
"portNames",
builder.getArrayAttr(portNames));
1839 if (!result.attributes.get(
"portTypes"))
1840 result.addAttribute(
"portTypes",
builder.getArrayAttr(portTypes));
1843 if (!result.attributes.get(
"portSyms")) {
1844 FModuleLike::fixupPortSymsArray(portSyms,
builder.getContext());
1845 result.addAttribute(
"portSyms",
builder.getArrayAttr(portSyms));
1849 if (!result.attributes.get(
"portLocations"))
1850 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1856 auto *bodyRegion = result.addRegion();
1858 if (hasSSAIdentifiers) {
1859 if (parser.parseRegion(*bodyRegion, entryArgs))
1861 if (bodyRegion->empty())
1862 bodyRegion->push_back(
new Block());
1872 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1873 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1874 p << visibility.getValue() <<
' ';
1877 p.printSymbolName(op.getName());
1881 Region ®ion = op->getRegion(0);
1882 Block *body =
nullptr;
1883 if (!region.empty())
1884 body = ®ion.front();
1887 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1888 {}, op.getPortSymbols(), op.getPortLocations());
1891 SmallVector<StringRef, 8> omittedAttrs = {
1892 "sym_name",
"portNames",
"portTypes",
"portDirections",
1893 "portSyms",
"portLocations", visibilityAttrName};
1897 if (!needPortNamesAttr)
1898 omittedAttrs.push_back(
"portNames");
1900 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1903 if (!region.empty()) {
1905 auto printEntryBlockArgs =
false;
1906 auto printBlockTerminators =
false;
1907 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
1915 void ClassOp::build(OpBuilder &
builder, OperationState &result, StringAttr name,
1916 ArrayRef<PortInfo> ports) {
1919 [](
const auto &port) {
return port.annotations.empty(); }) &&
1920 "class ports may not have annotations");
1925 auto *bodyRegion = result.regions[0].get();
1927 bodyRegion->push_back(body);
1930 for (
auto &elt : ports)
1931 body->addArgument(elt.type, elt.loc);
1934 void ClassOp::print(OpAsmPrinter &p) {
1938 ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
1939 auto hasSSAIdentifiers =
true;
1943 LogicalResult ClassOp::verify() {
1944 for (
auto operand : getBodyBlock()->getArguments()) {
1945 auto type = operand.getType();
1946 if (!isa<PropertyType>(type)) {
1947 emitOpError(
"ports on a class must be properties");
1956 ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
1960 void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1965 SmallVector<PortInfo> ClassOp::getPorts() {
1970 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1971 getBodyBlock()->eraseArguments(portIndices);
1975 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1978 Convention ClassOp::getConvention() {
return Convention::Internal; }
1980 ConventionAttr ClassOp::getConventionAttr() {
1984 ArrayAttr ClassOp::getParameters() {
return {}; }
1986 ArrayAttr ClassOp::getPortAnnotationsAttr() {
1990 ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
1992 ArrayRef<Attribute> ClassOp::getLayers() {
return getLayersAttr(); }
2002 BlockArgument ClassOp::getArgument(
size_t portNumber) {
2003 return getBodyBlock()->getArgument(portNumber);
2006 bool ClassOp::canDiscardOnUseEmpty() {
2017 void ExtClassOp::build(OpBuilder &
builder, OperationState &result,
2018 StringAttr name, ArrayRef<PortInfo> ports) {
2021 [](
const auto &port) {
return port.annotations.empty(); }) &&
2022 "class ports may not have annotations");
2027 void ExtClassOp::print(OpAsmPrinter &p) {
2031 ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2032 auto hasSSAIdentifiers =
false;
2037 ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2041 void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2046 SmallVector<PortInfo> ExtClassOp::getPorts() {
2051 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2055 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2058 Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2060 ConventionAttr ExtClassOp::getConventionAttr() {
2064 ArrayAttr ExtClassOp::getLayersAttr() {
2068 ArrayRef<Attribute> ExtClassOp::getLayers() {
return getLayersAttr(); }
2070 ArrayAttr ExtClassOp::getParameters() {
return {}; }
2072 ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2084 bool ExtClassOp::canDiscardOnUseEmpty() {
2096 auto circuit = (*this)->getParentOfType<CircuitOp>();
2098 llvm::report_fatal_error(
"instance op not in circuit");
2099 return circuit.lookupSymbol<hw::PortList>(getModuleNameAttr()).
getPortList();
2102 void InstanceOp::build(
2103 OpBuilder &
builder, OperationState &result, TypeRange resultTypes,
2104 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2105 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2106 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2107 ArrayRef<Attribute> layers,
bool lowerToBind, StringAttr innerSym) {
2108 build(
builder, result, resultTypes, moduleName, name, nameKind,
2109 portDirections, portNames, annotations, portAnnotations, layers,
2114 void InstanceOp::build(
2115 OpBuilder &
builder, OperationState &result, TypeRange resultTypes,
2116 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2117 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2118 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2119 ArrayRef<Attribute> layers,
bool lowerToBind, hw::InnerSymAttr innerSym) {
2120 result.addTypes(resultTypes);
2121 result.addAttribute(
"moduleName",
2123 result.addAttribute(
"name",
builder.getStringAttr(name));
2124 result.addAttribute(
2127 result.addAttribute(
"portNames",
builder.getArrayAttr(portNames));
2128 result.addAttribute(
"annotations",
builder.getArrayAttr(annotations));
2129 result.addAttribute(
"layers",
builder.getArrayAttr(layers));
2131 result.addAttribute(
"lowerToBind",
builder.getUnitAttr());
2133 result.addAttribute(
"inner_sym", innerSym);
2134 result.addAttribute(
"nameKind",
2137 if (portAnnotations.empty()) {
2138 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2140 result.addAttribute(
"portAnnotations",
2141 builder.getArrayAttr(portAnnotationsVec));
2143 assert(portAnnotations.size() == resultTypes.size());
2144 result.addAttribute(
"portAnnotations",
2145 builder.getArrayAttr(portAnnotations));
2149 void InstanceOp::build(OpBuilder &
builder, OperationState &result,
2150 FModuleLike module, StringRef name,
2151 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2152 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2153 hw::InnerSymAttr innerSym) {
2156 SmallVector<Type> resultTypes;
2157 resultTypes.reserve(module.getNumPorts());
2159 module.getPortTypes(), std::back_inserter(resultTypes),
2160 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2163 ArrayAttr portAnnotationsAttr;
2164 if (portAnnotations.empty()) {
2165 portAnnotationsAttr =
builder.getArrayAttr(SmallVector<Attribute, 16>(
2166 resultTypes.size(),
builder.getArrayAttr({})));
2168 portAnnotationsAttr =
builder.getArrayAttr(portAnnotations);
2176 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2177 builder.getArrayAttr(annotations), portAnnotationsAttr,
2178 module.getLayersAttr(), lowerToBind ?
builder.getUnitAttr() : UnitAttr(),
2182 void InstanceOp::build(OpBuilder &
builder, OperationState &odsState,
2183 ArrayRef<PortInfo> ports, StringRef moduleName,
2184 StringRef name, NameKindEnum nameKind,
2185 ArrayRef<Attribute> annotations,
2186 ArrayRef<Attribute> layers,
bool lowerToBind,
2187 hw::InnerSymAttr innerSym) {
2189 SmallVector<Type> newResultTypes;
2190 SmallVector<Direction> newPortDirections;
2191 SmallVector<Attribute> newPortNames;
2192 SmallVector<Attribute> newPortAnnotations;
2193 for (
auto &p : ports) {
2194 newResultTypes.push_back(p.type);
2195 newPortDirections.push_back(p.direction);
2196 newPortNames.push_back(p.name);
2197 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2200 return build(
builder, odsState, newResultTypes, moduleName, name, nameKind,
2201 newPortDirections, newPortNames, annotations, newPortAnnotations,
2202 layers, lowerToBind, innerSym);
2205 LogicalResult InstanceOp::verify() {
2208 SmallVector<SymbolRefAttr> missingLayers;
2209 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2211 missingLayers.push_back(layer);
2213 if (missingLayers.empty())
2217 emitOpError(
"ambient layers are insufficient to instantiate module");
2218 auto ¬e = diag.attachNote();
2219 note <<
"missing layer requirements: ";
2220 interleaveComma(missingLayers, note);
2227 const llvm::BitVector &portIndices) {
2228 assert(portIndices.size() >= getNumResults() &&
2229 "portIndices is not at least as large as getNumResults()");
2231 if (portIndices.none())
2234 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2235 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2236 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2238 SmallVector<Attribute> newPortNames =
2240 SmallVector<Attribute> newPortAnnotations =
2243 auto newOp =
builder.create<InstanceOp>(
2244 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2245 newPortDirections, newPortNames, getAnnotations().getValue(),
2246 newPortAnnotations, getLayers(), getLowerToBind(), getInnerSymAttr());
2248 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2249 oldIdx != numOldPorts; ++oldIdx) {
2250 if (portIndices.test(oldIdx)) {
2251 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2254 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2262 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2263 newOp->setAttr(
"output_file", outputFile);
2268 ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2269 assert(portIdx < getNumResults() &&
2270 "index should be smaller than result number");
2271 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2274 void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2275 assert(annotations.size() == getNumResults() &&
2276 "number of annotations is not equal to result number");
2277 (*this)->setAttr(
"portAnnotations",
2282 InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2283 auto portSize = ports.size();
2284 auto newPortCount = getNumResults() + portSize;
2285 SmallVector<Direction> newPortDirections;
2286 newPortDirections.reserve(newPortCount);
2287 SmallVector<Attribute> newPortNames;
2288 newPortNames.reserve(newPortCount);
2289 SmallVector<Type> newPortTypes;
2290 newPortTypes.reserve(newPortCount);
2291 SmallVector<Attribute> newPortAnnos;
2292 newPortAnnos.reserve(newPortCount);
2294 unsigned oldIndex = 0;
2295 unsigned newIndex = 0;
2296 while (oldIndex + newIndex < newPortCount) {
2298 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2299 auto &newPort = ports[newIndex].second;
2300 newPortDirections.push_back(newPort.direction);
2301 newPortNames.push_back(newPort.name);
2302 newPortTypes.push_back(newPort.type);
2303 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2307 newPortDirections.push_back(getPortDirection(oldIndex));
2308 newPortNames.push_back(getPortName(oldIndex));
2309 newPortTypes.push_back(getType(oldIndex));
2310 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2316 return OpBuilder(*this).create<InstanceOp>(
2317 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2318 newPortDirections, newPortNames, getAnnotations().getValue(),
2319 newPortAnnos, getLayers(), getLowerToBind(), getInnerSymAttr());
2322 LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2324 getModuleNameAttr());
2329 StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2331 void InstanceOp::print(OpAsmPrinter &p) {
2334 p.printKeywordOrString(
getName());
2335 if (
auto attr = getInnerSymAttr()) {
2337 p.printSymbolName(attr.getSymName());
2339 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2340 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2343 SmallVector<StringRef, 10> omittedAttrs = {
2344 "moduleName",
"name",
"portDirections",
2345 "portNames",
"portTypes",
"portAnnotations",
2346 "inner_sym",
"nameKind"};
2347 if (getAnnotations().
empty())
2348 omittedAttrs.push_back(
"annotations");
2349 if (getLayers().
empty())
2350 omittedAttrs.push_back(
"layers");
2351 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2355 p.printSymbolName(getModuleName());
2358 SmallVector<Attribute> portTypes;
2359 portTypes.reserve(getNumResults());
2360 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2363 getPortNames().getValue(), portTypes,
2364 getPortAnnotations().getValue(), {}, {});
2367 ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2368 auto *context = parser.getContext();
2369 auto &resultAttrs = result.attributes;
2372 hw::InnerSymAttr innerSymAttr;
2373 FlatSymbolRefAttr moduleName;
2374 SmallVector<OpAsmParser::Argument> entryArgs;
2375 SmallVector<Direction, 4> portDirections;
2376 SmallVector<Attribute, 4> portNames;
2377 SmallVector<Attribute, 4> portTypes;
2378 SmallVector<Attribute, 4> portAnnotations;
2379 SmallVector<Attribute, 4> portSyms;
2380 SmallVector<Attribute, 4> portLocs;
2381 NameKindEnumAttr nameKind;
2383 if (parser.parseKeywordOrString(&name))
2385 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2386 if (parser.parseCustomAttributeWithFallback(
2387 innerSymAttr, ::mlir::Type{},
2388 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2389 result.attributes)) {
2390 return ::mlir::failure();
2394 parser.parseOptionalAttrDict(result.attributes) ||
2395 parser.parseAttribute(moduleName,
"moduleName", resultAttrs) ||
2397 false, entryArgs, portDirections,
2398 portNames, portTypes, portAnnotations, portSyms,
2404 if (!resultAttrs.get(
"moduleName"))
2405 result.addAttribute(
"moduleName", moduleName);
2406 if (!resultAttrs.get(
"name"))
2408 result.addAttribute(
"nameKind", nameKind);
2409 if (!resultAttrs.get(
"portDirections"))
2410 result.addAttribute(
"portDirections",
2412 if (!resultAttrs.get(
"portNames"))
2413 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2414 if (!resultAttrs.get(
"portAnnotations"))
2415 result.addAttribute(
"portAnnotations",
2420 if (!resultAttrs.get(
"annotations"))
2421 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2422 if (!resultAttrs.get(
"layers"))
2423 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2426 result.types.reserve(portTypes.size());
2428 portTypes, std::back_inserter(result.types),
2429 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2439 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2440 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2444 std::optional<size_t> InstanceOp::getTargetResultIndex() {
2446 return std::nullopt;
2453 void InstanceChoiceOp::build(
2454 OpBuilder &
builder, OperationState &result, FModuleLike defaultModule,
2455 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2456 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2457 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2459 SmallVector<Type> resultTypes;
2460 for (Attribute portType : defaultModule.getPortTypes())
2461 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2464 ArrayAttr portAnnotationsAttr;
2465 if (portAnnotations.empty()) {
2466 portAnnotationsAttr =
builder.getArrayAttr(SmallVector<Attribute, 16>(
2467 resultTypes.size(),
builder.getArrayAttr({})));
2469 portAnnotationsAttr =
builder.getArrayAttr(portAnnotations);
2473 SmallVector<Attribute> moduleNames, caseNames;
2475 for (
auto [caseOption, caseModule] : cases) {
2476 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2478 {SymbolRefAttr::get(caseOption)}));
2482 return build(
builder, result, resultTypes,
builder.getArrayAttr(moduleNames),
2485 defaultModule.getPortDirectionsAttr(),
2486 defaultModule.getPortNamesAttr(),
2487 builder.getArrayAttr(annotations), portAnnotationsAttr,
2488 defaultModule.getLayersAttr(),
2492 std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2493 return std::nullopt;
2496 void InstanceChoiceOp::print(OpAsmPrinter &p) {
2499 p.printKeywordOrString(
getName());
2500 if (
auto attr = getInnerSymAttr()) {
2502 p.printSymbolName(attr.getSymName());
2504 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2505 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2508 SmallVector<StringRef, 10> omittedAttrs = {
2509 "moduleNames",
"caseNames",
"name",
2510 "portDirections",
"portNames",
"portTypes",
2511 "portAnnotations",
"inner_sym",
"nameKind"};
2512 if (getAnnotations().
empty())
2513 omittedAttrs.push_back(
"annotations");
2514 if (getLayers().
empty())
2515 omittedAttrs.push_back(
"layers");
2516 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2521 auto moduleNames = getModuleNamesAttr();
2522 auto caseNames = getCaseNamesAttr();
2524 p.printSymbolName(moduleNames[0].cast<FlatSymbolRefAttr>().getValue());
2526 p <<
" alternatives ";
2528 caseNames[0].cast<SymbolRefAttr>().getRootReference().getValue());
2530 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2534 auto symbol = caseNames[i].cast<SymbolRefAttr>();
2535 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2537 p.printSymbolName(moduleNames[i + 1].cast<FlatSymbolRefAttr>().getValue());
2543 SmallVector<Attribute> portTypes;
2544 portTypes.reserve(getNumResults());
2545 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2548 getPortNames().getValue(), portTypes,
2549 getPortAnnotations().getValue(), {}, {});
2552 ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2553 OperationState &result) {
2554 auto *context = parser.getContext();
2555 auto &resultAttrs = result.attributes;
2558 hw::InnerSymAttr innerSymAttr;
2559 SmallVector<Attribute> moduleNames;
2560 SmallVector<Attribute> caseNames;
2561 SmallVector<OpAsmParser::Argument> entryArgs;
2562 SmallVector<Direction, 4> portDirections;
2563 SmallVector<Attribute, 4> portNames;
2564 SmallVector<Attribute, 4> portTypes;
2565 SmallVector<Attribute, 4> portAnnotations;
2566 SmallVector<Attribute, 4> portSyms;
2567 SmallVector<Attribute, 4> portLocs;
2568 NameKindEnumAttr nameKind;
2570 if (parser.parseKeywordOrString(&name))
2572 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2573 if (parser.parseCustomAttributeWithFallback(
2574 innerSymAttr, Type{},
2575 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2576 result.attributes)) {
2581 parser.parseOptionalAttrDict(result.attributes))
2584 FlatSymbolRefAttr defaultModuleName;
2585 if (parser.parseAttribute(defaultModuleName))
2587 moduleNames.push_back(defaultModuleName);
2591 FlatSymbolRefAttr optionName;
2592 if (parser.parseKeyword(
"alternatives") ||
2593 parser.parseAttribute(optionName) || parser.parseLBrace())
2596 FlatSymbolRefAttr moduleName;
2597 StringAttr caseName;
2598 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2599 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2601 moduleNames.push_back(moduleName);
2603 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2604 if (failed(parser.parseOptionalComma()))
2607 if (parser.parseRBrace())
2612 false, entryArgs, portDirections,
2613 portNames, portTypes, portAnnotations, portSyms,
2619 if (!resultAttrs.get(
"moduleNames"))
2620 result.addAttribute(
"moduleNames",
ArrayAttr::get(context, moduleNames));
2621 if (!resultAttrs.get(
"caseNames"))
2622 result.addAttribute(
"caseNames",
ArrayAttr::get(context, caseNames));
2623 if (!resultAttrs.get(
"name"))
2625 result.addAttribute(
"nameKind", nameKind);
2626 if (!resultAttrs.get(
"portDirections"))
2627 result.addAttribute(
"portDirections",
2629 if (!resultAttrs.get(
"portNames"))
2630 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2631 if (!resultAttrs.get(
"portAnnotations"))
2632 result.addAttribute(
"portAnnotations",
2637 if (!resultAttrs.get(
"annotations"))
2638 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2639 if (!resultAttrs.get(
"layers"))
2640 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2643 result.types.reserve(portTypes.size());
2645 portTypes, std::back_inserter(result.types),
2646 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2653 for (
auto [result, name] : llvm::zip(getResults(), getPortNames()))
2654 setNameFn(result, (base +
"_" + name.cast<StringAttr>().getValue()).str());
2657 LogicalResult InstanceChoiceOp::verify() {
2658 if (getCaseNamesAttr().
empty())
2659 return emitOpError() <<
"must have at least one case";
2660 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2661 return emitOpError() <<
"number of referenced modules does not match the "
2662 "number of options";
2667 SmallVector<SymbolRefAttr> missingLayers;
2668 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2670 missingLayers.push_back(layer);
2672 if (missingLayers.empty())
2676 emitOpError(
"ambient layers are insufficient to instantiate module");
2677 auto ¬e = diag.attachNote();
2678 note <<
"missing layer requirements: ";
2679 interleaveComma(missingLayers, note);
2684 InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2685 auto caseNames = getCaseNamesAttr();
2686 for (
auto moduleName : getModuleNamesAttr()) {
2688 *
this, symbolTable, moduleName.cast<FlatSymbolRefAttr>())))
2692 auto root = caseNames[0].cast<SymbolRefAttr>().getRootReference();
2693 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2694 auto ref = caseNames[i].cast<SymbolRefAttr>();
2695 auto refRoot = ref.getRootReference();
2696 if (ref.getRootReference() != root)
2697 return emitOpError() <<
"case " << ref
2698 <<
" is not in the same option group as "
2701 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2702 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2704 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2705 return emitOpError() <<
"option " << refRoot
2706 <<
" does not contain option case " << ref;
2713 InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2714 auto caseNames = getCaseNamesAttr();
2715 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2716 StringAttr caseSym = caseNames[i].cast<SymbolRefAttr>().getLeafReference();
2717 if (caseSym == option.getSymName())
2718 return getModuleNamesAttr()[i + 1].cast<FlatSymbolRefAttr>();
2720 return getDefaultTargetAttr();
2723 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2724 InstanceChoiceOp::getTargetChoices() {
2725 auto caseNames = getCaseNamesAttr();
2726 auto moduleNames = getModuleNamesAttr();
2727 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2728 for (
size_t i = 0; i < caseNames.size(); ++i) {
2729 choices.emplace_back(caseNames[i].cast<SymbolRefAttr>(),
2730 moduleNames[i + 1].cast<FlatSymbolRefAttr>());
2740 void MemOp::build(OpBuilder &
builder, OperationState &result,
2741 TypeRange resultTypes, uint32_t readLatency,
2742 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2743 ArrayRef<Attribute> portNames, StringRef name,
2744 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2745 ArrayRef<Attribute> portAnnotations,
2746 hw::InnerSymAttr innerSym) {
2747 result.addAttribute(
2749 builder.getIntegerAttr(
builder.getIntegerType(32), readLatency));
2750 result.addAttribute(
2752 builder.getIntegerAttr(
builder.getIntegerType(32), writeLatency));
2753 result.addAttribute(
2754 "depth",
builder.getIntegerAttr(
builder.getIntegerType(64), depth));
2756 result.addAttribute(
"portNames",
builder.getArrayAttr(portNames));
2757 result.addAttribute(
"name",
builder.getStringAttr(name));
2758 result.addAttribute(
"nameKind",
2760 result.addAttribute(
"annotations",
builder.getArrayAttr(annotations));
2762 result.addAttribute(
"inner_sym", innerSym);
2763 result.addTypes(resultTypes);
2765 if (portAnnotations.empty()) {
2766 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2768 result.addAttribute(
"portAnnotations",
2769 builder.getArrayAttr(portAnnotationsVec));
2771 assert(portAnnotations.size() == resultTypes.size());
2772 result.addAttribute(
"portAnnotations",
2773 builder.getArrayAttr(portAnnotations));
2777 void MemOp::build(OpBuilder &
builder, OperationState &result,
2778 TypeRange resultTypes, uint32_t readLatency,
2779 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2780 ArrayRef<Attribute> portNames, StringRef name,
2781 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2782 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2783 build(
builder, result, resultTypes, readLatency, writeLatency, depth, ruw,
2784 portNames, name, nameKind, annotations, portAnnotations,
2788 ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2789 assert(portIdx < getNumResults() &&
2790 "index should be smaller than result number");
2791 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2794 void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2795 assert(annotations.size() == getNumResults() &&
2796 "number of annotations is not equal to result number");
2797 (*this)->setAttr(
"portAnnotations",
2803 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2806 numReadWritePorts = 0;
2808 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2809 auto portKind = getPortKind(i);
2810 if (portKind == MemOp::PortKind::Debug)
2812 else if (portKind == MemOp::PortKind::Read)
2814 else if (portKind == MemOp::PortKind::Write) {
2817 ++numReadWritePorts;
2822 LogicalResult MemOp::verify() {
2826 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2832 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2833 auto portName = getPortName(i);
2838 BundleType portBundleType =
2839 type_dyn_cast<BundleType>(getResult(i).getType());
2842 if (!portNamesSet.insert(portName).second) {
2843 emitOpError() <<
"has non-unique port name " << portName;
2851 auto elt = getPortNamed(portName);
2853 emitOpError() <<
"could not get port with name " << portName;
2856 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2859 if (portKind == MemOp::PortKind::Debug &&
2860 !type_isa<RefType>(getResult(i).getType()))
2861 return emitOpError() <<
"has an invalid type on port " << portName
2862 <<
" (expected Read/Write/ReadWrite/Debug)";
2863 if (type_isa<RefType>(firrtlType) && e == 1)
2864 return emitOpError()
2865 <<
"cannot have only one port of debug type. Debug port can only "
2866 "exist alongside other read/write/read-write port";
2871 if (portKind == MemOp::PortKind::Debug) {
2872 auto resType = type_cast<RefType>(getResult(i).getType());
2873 if (!(resType && type_isa<FVectorType>(resType.getType())))
2874 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2875 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2877 auto dataTypeOption = portBundleType.getElement(
"data");
2878 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2879 dataTypeOption = portBundleType.getElement(
"wdata");
2880 if (!dataTypeOption) {
2881 emitOpError() <<
"has no data field on port " << portName
2882 <<
" (expected to see \"data\" for a read or write "
2883 "port or \"rdata\" for a read/write port)";
2886 dataType = dataTypeOption->type;
2888 if (portKind == MemOp::PortKind::Read) {
2895 emitOpError() <<
"has non-passive data type on port " << portName
2896 <<
" (memory types must be passive)";
2901 if (dataType.containsAnalog()) {
2902 emitOpError() <<
"has a data type that contains an analog type on port "
2904 <<
" (memory types cannot contain analog types)";
2912 getTypeForPort(getDepth(), dataType, portKind,
2913 dataType.isGround() ? getMaskBits() : 0);
2916 auto originalType = getResult(i).getType();
2917 if (originalType != expectedType) {
2918 StringRef portKindName;
2920 case MemOp::PortKind::Read:
2921 portKindName =
"read";
2923 case MemOp::PortKind::Write:
2924 portKindName =
"write";
2926 case MemOp::PortKind::ReadWrite:
2927 portKindName =
"readwrite";
2929 case MemOp::PortKind::Debug:
2930 portKindName =
"dbg";
2933 emitOpError() <<
"has an invalid type for port " << portName
2934 <<
" of determined kind \"" << portKindName
2935 <<
"\" (expected " << expectedType <<
", but got "
2936 << originalType <<
")";
2942 if (oldDataType && oldDataType != dataType) {
2943 emitOpError() <<
"port " << getPortName(i)
2944 <<
" has a different type than port " << getPortName(i - 1)
2945 <<
" (expected " << oldDataType <<
", but got " << dataType
2950 oldDataType = dataType;
2953 auto maskWidth = getMaskBits();
2955 auto dataWidth = getDataType().getBitWidthOrSentinel();
2956 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
2957 return emitOpError(
"the mask width cannot be greater than "
2960 if (getPortAnnotations().size() != getNumResults())
2961 return emitOpError(
"the number of result annotations should be "
2962 "equal to the number of results");
2968 return std::max(1U, llvm::Log2_64_Ceil(depth));
2974 PortKind portKind,
size_t maskBits) {
2976 auto *context = dataType.getContext();
2977 if (portKind == PortKind::Debug)
2986 auto getId = [&](StringRef name) -> StringAttr {
2990 SmallVector<BundleType::BundleElement, 7> portFields;
2994 portFields.push_back({getId(
"addr"),
false, addressType});
2995 portFields.push_back({getId(
"en"),
false,
UIntType::get(context, 1)});
2996 portFields.push_back({getId(
"clk"),
false,
ClockType::get(context)});
2999 case PortKind::Read:
3000 portFields.push_back({getId(
"data"),
true, dataType});
3003 case PortKind::Write:
3004 portFields.push_back({getId(
"data"),
false, dataType});
3005 portFields.push_back({getId(
"mask"),
false, maskType});
3008 case PortKind::ReadWrite:
3009 portFields.push_back({getId(
"rdata"),
true, dataType});
3010 portFields.push_back({getId(
"wmode"),
false,
UIntType::get(context, 1)});
3011 portFields.push_back({getId(
"wdata"),
false, dataType});
3012 portFields.push_back({getId(
"wmask"),
false, maskType});
3015 llvm::report_fatal_error(
"memory port kind not handled");
3023 SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3024 SmallVector<MemOp::NamedPort> result;
3026 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3028 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3035 MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3037 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3041 MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3043 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3047 size_t MemOp::getMaskBits() {
3049 for (
auto res : getResults()) {
3050 if (type_isa<RefType>(res.getType()))
3052 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3058 for (
auto t : type_cast<BundleType>(firstPortType.getPassiveType())) {
3059 if (t.name.getValue().contains(
"mask"))
3062 if (type_isa<UIntType>(mType))
3072 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3074 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3075 return type_cast<FVectorType>(refType.getType()).getElementType();
3076 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3078 StringRef dataFieldName =
"data";
3080 dataFieldName =
"rdata";
3082 return type_cast<BundleType>(firstPortType.getPassiveType())
3083 .getElementType(dataFieldName);
3086 StringAttr MemOp::getPortName(
size_t resultNo) {
3087 return cast<StringAttr>(getPortNames()[resultNo]);
3091 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3094 Value MemOp::getPortNamed(StringAttr name) {
3095 auto namesArray = getPortNames();
3096 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3097 if (namesArray[i] == name) {
3098 assert(i < getNumResults() &&
" names array out of sync with results");
3099 return getResult(i);
3108 size_t numReadPorts = 0;
3109 size_t numWritePorts = 0;
3110 size_t numReadWritePorts = 0;
3112 SmallVector<int32_t> writeClockIDs;
3114 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3115 auto portKind = op.getPortKind(i);
3116 if (portKind == MemOp::PortKind::Read)
3118 else if (portKind == MemOp::PortKind::Write) {
3119 for (
auto *a : op.getResult(i).getUsers()) {
3120 auto subfield = dyn_cast<SubfieldOp>(a);
3121 if (!subfield || subfield.getFieldIndex() != 2)
3123 auto clockPort = a->getResult(0);
3124 for (
auto *b : clockPort.getUsers()) {
3125 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3126 if (
connect.getDest() == clockPort) {
3129 connect.getSrc(),
true,
true,
true),
3131 if (result.second) {
3132 writeClockIDs.push_back(numWritePorts);
3134 writeClockIDs.push_back(result.first->second);
3143 ++numReadWritePorts;
3150 op.emitError(
"'firrtl.mem' should have simple type and known width");
3151 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3153 if (op->hasAttr(
"modName"))
3154 modName = op->getAttrOfType<StringAttr>(
"modName");
3156 SmallString<8> clocks;
3157 for (
auto a : writeClockIDs)
3158 clocks.append(Twine((
char)(a +
'a')).str());
3159 SmallString<32> initStr;
3164 for (
auto c : init.getFilename().getValue())
3165 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3166 (c >=
'0' && c <=
'9'))
3167 initStr.push_back(c);
3168 initStr.push_back(
'_');
3169 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3170 initStr.push_back(
'_');
3171 initStr.push_back(init.getIsInline() ?
't' :
'f');
3176 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3177 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3178 numReadWritePorts, (
size_t)
width, op.getDepth(),
3179 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3180 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3181 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3183 return {numReadPorts,
3188 op.getReadLatency(),
3189 op.getWriteLatency(),
3191 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3192 seq::WUW::PortOrder,
3195 op.getMaskBits() > 1,
3206 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3207 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3211 std::optional<size_t> MemOp::getTargetResultIndex() {
3213 return std::nullopt;
3217 StringAttr FirMemory::getFirMemoryName()
const {
return modName; }
3224 setNameFn(op.getDataRaw(), name);
3225 if (op.isForceable())
3226 setNameFn(op.getDataRef(), (name +
"_ref").str());
3234 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3235 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3236 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3237 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3238 if (operands.empty())
3240 inferredReturnTypes.push_back(operands[0].getType());
3241 for (
auto &attr : attributes)
3242 if (attr.getName() == Forceable::getForceableAttrName()) {
3243 auto forceableType =
3245 if (!forceableType) {
3247 ::mlir::emitError(*location,
"cannot force a node of type ")
3248 << operands[0].getType();
3251 inferredReturnTypes.push_back(forceableType);
3256 std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3262 std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3264 LogicalResult RegResetOp::verify() {
3265 auto reset = getResetValue();
3272 return emitError(
"type mismatch between register ")
3273 << regType <<
" and reset value " << resetType;
3278 std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3288 std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3290 LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3291 auto refType = type_dyn_cast<RefType>(getType(0));
3296 refType, getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3297 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3300 void ObjectOp::build(OpBuilder &
builder, OperationState &state, ClassLike klass,
3302 build(
builder, state, klass.getInstanceType(),
3306 LogicalResult ObjectOp::verify() {
return success(); }
3308 LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3309 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3310 auto classType = getType();
3311 auto className = classType.getNameAttr();
3314 auto classOp = dyn_cast_or_null<ClassLike>(
3315 symbolTable.lookupSymbolIn(circuitOp, className));
3317 return emitOpError() <<
"references unknown class " << className;
3320 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3326 StringAttr ObjectOp::getClassNameAttr() {
3327 return getType().getNameAttr().getAttr();
3330 StringRef ObjectOp::getClassName() {
return getType().getName(); }
3332 ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3333 auto symRef = getType().getNameAttr();
3334 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3337 Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3338 return getReferencedClass(symtbl);
3343 StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3345 StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3347 StringAttr ObjectOp::getReferencedModuleNameAttr() {
3348 return getClassNameAttr();
3352 setNameFn(getResult(),
getName());
3359 LogicalResult AttachOp::verify() {
3361 std::optional<int32_t> commonWidth;
3362 for (
auto operand : getOperands()) {
3363 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3367 commonWidth = thisWidth;
3370 if (commonWidth != thisWidth)
3371 return emitOpError(
"is inavlid as not all known operand widths match");
3378 Value dst =
connect->getOperand(0);
3379 Value src =
connect->getOperand(1);
3390 auto diag = emitError(
connect->getLoc());
3391 diag <<
"connect has invalid flow: the source expression ";
3393 diag <<
"\"" << srcName <<
"\" ";
3394 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3395 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3403 auto diag = emitError(
connect->getLoc());
3404 diag <<
"connect has invalid flow: the destination expression ";
3406 diag <<
"\"" << dstName <<
"\" ";
3407 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3408 return diag.attachNote(dstRef.getLoc())
3409 <<
"the destination was defined here";
3418 bool outerTypeIsConst =
false) {
3419 auto typeIsConst = outerTypeIsConst || type.
isConst();
3424 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3425 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3426 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3430 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3442 auto dest =
connect.getDest();
3443 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3445 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3446 if (!destType || !srcType)
3449 auto destRefinedType = destType;
3450 auto srcRefinedType = srcType;
3455 auto findFieldDeclarationRefiningFieldType =
3457 while (
auto *definingOp = value.getDefiningOp()) {
3458 bool shouldContinue =
true;
3459 TypeSwitch<Operation *>(definingOp)
3460 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3461 .Case<SubaccessOp>([&](SubaccessOp op) {
3465 .getElementTypePreservingConst()
3467 originalFieldType = originalFieldType.getConstType(
true);
3468 value = op.getInput();
3470 .Default([&](Operation *) { shouldContinue =
false; });
3471 if (!shouldContinue)
3477 auto destDeclaration =
3478 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3479 auto srcDeclaration =
3480 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3482 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3483 Value declaration) -> LogicalResult {
3484 auto *declarationBlock = declaration.getParentBlock();
3485 auto *block =
connect->getBlock();
3486 while (block && block != declarationBlock) {
3487 auto *parentOp = block->getParentOp();
3489 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3490 whenOp && !whenOp.getCondition().getType().isConst()) {
3493 <<
"assignment to 'const' type " << type
3494 <<
" is dependent on a non-'const' condition";
3496 <<
"assignment to nested 'const' member of type " << type
3497 <<
" is dependent on a non-'const' condition";
3500 block = parentOp->getBlock();
3505 auto emitSubaccessError = [&] {
3507 "assignment to non-'const' subaccess of 'const' type is disallowed");
3513 if (destType != destRefinedType)
3514 return emitSubaccessError();
3516 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3521 if (srcRefinedType.containsConst() &&
3524 if (srcType != srcRefinedType)
3525 return emitSubaccessError();
3526 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3533 LogicalResult ConnectOp::verify() {
3534 auto dstType = getDest().getType();
3535 auto srcType = getSrc().getType();
3536 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3537 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3538 if (!dstBaseType || !srcBaseType) {
3539 if (dstType != srcType)
3540 return emitError(
"may not connect different non-base types");
3543 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3544 return emitError(
"analog types may not be connected");
3548 return emitError(
"type mismatch between destination ")
3549 << dstBaseType <<
" and source " << srcBaseType;
3554 return emitError(
"destination ")
3555 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3568 LogicalResult StrictConnectOp::verify() {
3569 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3570 auto baseType = type_cast<FIRRTLBaseType>(type);
3573 if (baseType && baseType.containsAnalog())
3574 return emitError(
"analog types may not be connected");
3579 "`SameAnonTypeOperands` trait should have already rejected "
3580 "structurally non-equivalent types");
3593 LogicalResult RefDefineOp::verify() {
3603 for (
auto *user : getDest().getUsers()) {
3604 if (
auto conn = dyn_cast<FConnectLike>(user);
3605 conn && conn.getDest() == getDest() && conn != *
this)
3606 return emitError(
"destination reference cannot be reused by multiple "
3607 "operations, it can only capture a unique dataflow");
3611 if (
auto *op = getDest().getDefiningOp()) {
3613 if (isa<RefSubOp>(op))
3615 "destination reference cannot be a sub-element of a reference");
3616 if (isa<RefCastOp>(op))
3618 "destination reference cannot be a cast of another reference");
3626 SmallVector<SymbolRefAttr> missingLayers;
3628 auto diag = emitOpError(
"has more layer requirements than destination");
3629 auto ¬e = diag.attachNote();
3630 note <<
"additional layers required: ";
3631 interleaveComma(missingLayers, note);
3638 LogicalResult PropAssignOp::verify() {
3644 for (
auto *user : getDest().getUsers()) {
3645 if (
auto conn = dyn_cast<FConnectLike>(user);
3646 conn && conn.getDest() == getDest() && conn != *
this)
3647 return emitError(
"destination property cannot be reused by multiple "
3648 "operations, it can only capture a unique dataflow");
3654 void WhenOp::createElseRegion() {
3655 assert(!hasElseRegion() &&
"already has an else region");
3656 getElseRegion().push_back(
new Block());
3659 void WhenOp::build(OpBuilder &
builder, OperationState &result, Value condition,
3660 bool withElseRegion, std::function<
void()> thenCtor,
3661 std::function<
void()> elseCtor) {
3662 OpBuilder::InsertionGuard guard(
builder);
3663 result.addOperands(condition);
3666 builder.createBlock(result.addRegion());
3671 Region *elseRegion = result.addRegion();
3672 if (withElseRegion) {
3673 builder.createBlock(elseRegion);
3683 LogicalResult MatchOp::verify() {
3684 FEnumType type = getInput().getType();
3687 auto numCases = getTags().size();
3688 auto numRegions = getNumRegions();
3689 if (numRegions != numCases)
3690 return emitOpError(
"expected ")
3691 << numRegions <<
" tags but got " << numCases;
3693 auto numTags = type.getNumElements();
3695 SmallDenseSet<int64_t> seen;
3696 for (
const auto &[tag, region] : llvm::zip(getTags(), getRegions())) {
3697 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3700 if (region.getNumArguments() != 1)
3701 return emitOpError(
"region should have exactly one argument");
3704 if (tagIndex >= numTags)
3705 return emitOpError(
"the tag index ")
3706 << tagIndex <<
" is out of the range of valid tags in " << type;
3709 auto [it, inserted] = seen.insert(tagIndex);
3711 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3712 <<
" is matched more than once";
3715 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3716 auto regionType = region.getArgument(0).getType();
3717 if (regionType != expectedType)
3718 return emitOpError(
"region type ")
3719 << regionType <<
" does not match the expected type "
3724 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3725 if (!seen.contains(i))
3726 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3731 void MatchOp::print(OpAsmPrinter &p) {
3732 auto input = getInput();
3733 FEnumType type = input.getType();
3734 auto regions = getRegions();
3735 p <<
" " << input <<
" : " << type;
3736 SmallVector<StringRef> elided = {
"tags"};
3737 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3740 for (
const auto &[tag, region] : llvm::zip(getTags(), regions)) {
3743 p.printKeywordOrString(
3744 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3746 p.printRegionArgument(region.front().getArgument(0), {},
3749 p.printRegion(region,
false);
3756 ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3757 auto *context = parser.getContext();
3758 OpAsmParser::UnresolvedOperand input;
3759 if (parser.parseOperand(input) || parser.parseColon())
3762 auto loc = parser.getCurrentLocation();
3764 if (parser.parseType(type))
3766 auto enumType = type_dyn_cast<FEnumType>(type);
3768 return parser.emitError(loc,
"expected enumeration type but got") << type;
3770 if (parser.resolveOperand(input, type, result.operands) ||
3771 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
3772 parser.parseLBrace())
3776 SmallVector<Attribute> tags;
3779 if (failed(parser.parseOptionalKeyword(
"case")))
3783 auto nameLoc = parser.getCurrentLocation();
3785 OpAsmParser::Argument arg;
3786 auto *region = result.addRegion();
3787 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
3788 parser.parseArgument(arg) || parser.parseRParen())
3792 auto index = enumType.getElementIndex(name);
3794 return parser.emitError(nameLoc,
"the tag \"")
3795 << name <<
"\" is not a member of the enumeration " << enumType;
3799 arg.type = enumType.getElementTypePreservingConst(*index);
3800 if (parser.parseRegion(*region, arg))
3805 return parser.parseRBrace();
3808 void MatchOp::build(OpBuilder &
builder, OperationState &result, Value input,
3810 MutableArrayRef<std::unique_ptr<Region>> regions) {
3811 result.addOperands(input);
3812 result.addAttribute(
"tags", tags);
3813 result.addRegions(regions);
3826 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
3827 DictionaryAttr attrs, mlir::OpaqueProperties properties,
3828 RegionRange regions, SmallVectorImpl<Type> &results,
3829 llvm::function_ref<
FIRRTLType(ValueRange, ArrayRef<NamedAttribute>,
3830 std::optional<Location>)>
3832 auto type = callback(
3833 operands, attrs ? attrs.getValue() : ArrayRef<NamedAttribute>{}, loc);
3835 results.push_back(type);
3843 static Attribute
maybeGetAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3844 for (
auto attr : attrs)
3845 if (attr.getName() == name)
3846 return attr.getValue();
3852 static Attribute
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3855 llvm::report_fatal_error(
"attribute '" + name +
"' not found");
3859 template <
typename AttrClass>
3860 AttrClass
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3861 return cast<AttrClass>(
getAttr(attrs, name));
3866 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
3867 bool visitInvalidExpr(Operation *op) {
return false; }
3868 bool visitUnhandledExpr(Operation *op) {
return true; }
3877 if (
auto ty = type_dyn_cast<IntType>(getType())) {
3878 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
3879 auto width = ty.getWidthOrSentinel();
3883 name = (Twine(base) + Twine(
width)).str();
3884 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
3885 auto width = ty.getWidthOrSentinel();
3887 name =
"invalid_analog";
3889 name = (
"invalid_analog" + Twine(
width)).str();
3890 }
else if (type_isa<AsyncResetType>(getType()))
3891 name =
"invalid_asyncreset";
3892 else if (type_isa<ResetType>(getType()))
3893 name =
"invalid_reset";
3894 else if (type_isa<ClockType>(getType()))
3895 name =
"invalid_clock";
3899 setNameFn(getResult(), name);
3902 void ConstantOp::print(OpAsmPrinter &p) {
3904 p.printAttributeWithoutType(getValueAttr());
3906 p.printType(getType());
3907 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
3910 ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
3913 auto loc = parser.getCurrentLocation();
3914 auto valueResult = parser.parseOptionalInteger(value);
3915 if (!valueResult.has_value())
3916 return parser.emitError(loc,
"expected integer value");
3920 if (failed(*valueResult) || parser.parseColonType(resultType) ||
3921 parser.parseOptionalAttrDict(result.attributes))
3923 result.addTypes(resultType);
3929 if (
width > value.getBitWidth()) {
3933 value = value.sext(
width);
3934 }
else if (
width < value.getBitWidth()) {
3937 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
3938 : value.getActiveBits();
3939 if (
width < neededBits)
3940 return parser.emitError(loc,
"constant out of range for result type ")
3942 value = value.trunc(
width);
3946 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
3948 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
3949 result.addAttribute(
"value", valueAttr);
3953 LogicalResult ConstantOp::verify() {
3959 "firrtl.constant attribute bitwidth doesn't match return type");
3962 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
3963 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
3964 return emitError(
"firrtl.constant attribute has wrong sign");
3971 void ConstantOp::build(OpBuilder &
builder, OperationState &result,
IntType type,
3972 const APInt &value) {
3976 "incorrect attribute bitwidth for firrtl.constant");
3980 return build(
builder, result, type, attr);
3985 void ConstantOp::build(OpBuilder &
builder, OperationState &result,
3986 const APSInt &value) {
3990 return build(
builder, result, type, attr);
4000 SmallString<32> specialNameBuffer;
4001 llvm::raw_svector_ostream specialName(specialNameBuffer);
4003 getValue().print(specialName, intTy.
isSigned());
4005 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4008 specialName <<
width;
4009 setNameFn(getResult(), specialName.str());
4012 void SpecialConstantOp::print(OpAsmPrinter &p) {
4015 p << static_cast<unsigned>(getValue());
4017 p.printType(getType());
4018 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4021 ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4022 OperationState &result) {
4026 auto loc = parser.getCurrentLocation();
4027 auto valueResult = parser.parseOptionalInteger(value);
4028 if (!valueResult.has_value())
4029 return parser.emitError(loc,
"expected integer value");
4032 if (value != 0 && value != 1)
4033 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4037 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4038 parser.parseOptionalAttrDict(result.attributes))
4040 result.addTypes(resultType);
4043 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4044 result.addAttribute(
"value", valueAttr);
4049 SmallString<32> specialNameBuffer;
4050 llvm::raw_svector_ostream specialName(specialNameBuffer);
4052 specialName << static_cast<unsigned>(getValue());
4053 auto type = getType();
4054 if (type_isa<ClockType>(type)) {
4055 specialName <<
"_clock";
4056 }
else if (type_isa<ResetType>(type)) {
4057 specialName <<
"_reset";
4058 }
else if (type_isa<AsyncResetType>(type)) {
4059 specialName <<
"_asyncreset";
4061 setNameFn(getResult(), specialName.str());
4068 if (type.isGround()) {
4069 if (!isa<IntegerAttr>(attr)) {
4070 op->emitOpError(
"Ground type is not an integer attribute");
4075 auto attrlist = dyn_cast<ArrayAttr>(attr);
4077 op->emitOpError(
"expected array attribute for aggregate constant");
4080 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4081 if (array.getNumElements() != attrlist.size()) {
4082 op->emitOpError(
"array attribute (")
4083 << attrlist.size() <<
") has wrong size for vector constant ("
4084 << array.getNumElements() <<
")";
4087 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4091 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4092 if (bundle.getNumElements() != attrlist.size()) {
4093 op->emitOpError(
"array attribute (")
4094 << attrlist.size() <<
") has wrong size for bundle constant ("
4095 << bundle.getNumElements() <<
")";
4098 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4099 if (bundle.getElement(i).isFlip) {
4100 op->emitOpError(
"Cannot have constant bundle type with flip");
4108 op->emitOpError(
"Unknown aggregate type");
4112 LogicalResult AggregateConstantOp::verify() {
4118 Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4120 Attribute value = getFields();
4121 while (fieldID != 0) {
4122 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4123 auto index = bundle.getIndexForFieldID(fieldID);
4124 fieldID -= bundle.getFieldID(index);
4125 type = bundle.getElementType(index);
4126 value = cast<ArrayAttr>(value)[index];
4128 auto vector = type_cast<FVectorType>(type);
4129 auto index = vector.getIndexForFieldID(fieldID);
4130 fieldID -= vector.getFieldID(index);
4131 type = vector.getElementType();
4132 value = cast<ArrayAttr>(value)[index];
4138 void FIntegerConstantOp::print(OpAsmPrinter &p) {
4140 p.printAttributeWithoutType(getValueAttr());
4141 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4144 ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4145 OperationState &result) {
4146 auto *context = parser.getContext();
4148 if (parser.parseInteger(value) ||
4149 parser.parseOptionalAttrDict(result.attributes))
4154 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4155 result.addAttribute(
"value", valueAttr);
4159 ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4160 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4163 if (parser.parseOperandList(operands) ||
4164 parser.parseOptionalAttrDict(result.attributes) ||
4165 parser.parseColonType(type))
4167 result.addTypes(type);
4169 return parser.resolveOperands(operands, type.getElementType(),
4173 void ListCreateOp::print(OpAsmPrinter &p) {
4175 p.printOperands(getElements());
4176 p.printOptionalAttrDict((*this)->getAttrs());
4177 p <<
" : " << getType();
4180 LogicalResult ListCreateOp::verify() {
4181 if (getElements().
empty())
4184 auto elementType = getElements().front().getType();
4185 auto listElementType = getType().getElementType();
4187 return emitOpError(
"has elements of type ")
4188 <<
elementType <<
" instead of " << listElementType;
4193 LogicalResult BundleCreateOp::verify() {
4194 BundleType resultType = getType();
4195 if (resultType.getNumElements() != getFields().size())
4196 return emitOpError(
"number of fields doesn't match type");
4197 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4199 resultType.getElementTypePreservingConst(i),
4200 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4201 return emitOpError(
"type of element doesn't match bundle for field ")
4202 << resultType.getElement(i).name;
4207 LogicalResult VectorCreateOp::verify() {
4208 FVectorType resultType = getType();
4209 if (resultType.getNumElements() != getFields().size())
4210 return emitOpError(
"number of fields doesn't match type");
4211 auto elemTy = resultType.getElementTypePreservingConst();
4212 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4214 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4215 return emitOpError(
"type of element doesn't match vector element");
4224 LogicalResult FEnumCreateOp::verify() {
4225 FEnumType resultType = getResult().getType();
4226 auto elementIndex = resultType.getElementIndex(
getFieldName());
4228 return emitOpError(
"label ")
4229 <<
getFieldName() <<
" is not a member of the enumeration type "
4232 resultType.getElementTypePreservingConst(*elementIndex),
4233 getInput().getType()))
4234 return emitOpError(
"type of element doesn't match enum element");
4238 void FEnumCreateOp::print(OpAsmPrinter &printer) {
4241 printer <<
'(' << getInput() <<
')';
4242 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4243 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4245 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4246 ArrayRef<Type>{getResult().getType()});
4249 ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4250 auto *context = parser.getContext();
4252 OpAsmParser::UnresolvedOperand input;
4253 std::string fieldName;
4254 mlir::FunctionType functionType;
4255 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4256 parser.parseOperand(input) || parser.parseRParen() ||
4257 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4258 parser.parseType(functionType))
4261 if (functionType.getNumInputs() != 1)
4262 return parser.emitError(parser.getNameLoc(),
"single input type required");
4263 if (functionType.getNumResults() != 1)
4264 return parser.emitError(parser.getNameLoc(),
"single result type required");
4266 auto inputType = functionType.getInput(0);
4267 if (parser.resolveOperand(input, inputType, result.operands))
4270 auto outputType = functionType.getResult(0);
4271 auto enumType = type_dyn_cast<FEnumType>(outputType);
4273 return parser.emitError(parser.getNameLoc(),
4274 "output must be enum type, got ")
4276 auto fieldIndex = enumType.getElementIndex(fieldName);
4278 return parser.emitError(parser.getNameLoc(),
4279 "unknown field " + fieldName +
" in enum type ")
4282 result.addAttribute(
4286 result.addTypes(enumType);
4295 LogicalResult IsTagOp::verify() {
4296 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4297 return emitOpError(
"element index is greater than the number of fields in "
4302 void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4303 printer <<
' ' << getInput() <<
' ';
4305 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4306 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4307 printer <<
" : " << getInput().getType();
4310 ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4311 auto *context = parser.getContext();
4313 OpAsmParser::UnresolvedOperand input;
4314 std::string fieldName;
4316 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4317 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4318 parser.parseType(inputType))
4321 if (parser.resolveOperand(input, inputType, result.operands))
4324 auto enumType = type_dyn_cast<FEnumType>(inputType);
4326 return parser.emitError(parser.getNameLoc(),
4327 "input must be enum type, got ")
4329 auto fieldIndex = enumType.getElementIndex(fieldName);
4331 return parser.emitError(parser.getNameLoc(),
4332 "unknown field " + fieldName +
" in enum type ")
4335 result.addAttribute(
4344 FIRRTLType IsTagOp::inferReturnType(ValueRange operands,
4345 ArrayRef<NamedAttribute> attrs,
4346 std::optional<Location> loc) {
4348 isConst(operands[0].getType()));
4351 template <
typename OpTy>
4353 auto *context = parser.getContext();
4355 OpAsmParser::UnresolvedOperand input;
4356 std::string fieldName;
4358 if (parser.parseOperand(input) || parser.parseLSquare() ||
4359 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4360 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4361 parser.parseType(inputType))
4364 if (parser.resolveOperand(input, inputType, result.operands))
4367 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4369 return parser.emitError(parser.getNameLoc(),
4370 "input must be bundle type, got ")
4372 auto fieldIndex = bundleType.getElementIndex(fieldName);
4374 return parser.emitError(parser.getNameLoc(),
4375 "unknown field " + fieldName +
" in bundle type ")
4378 result.addAttribute(
4382 SmallVector<Type> inferredReturnTypes;
4384 result.attributes.getDictionary(context),
4385 result.getRawProperties(), result.regions,
4386 inferredReturnTypes)))
4388 result.addTypes(inferredReturnTypes);
4393 ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4394 auto *context = parser.getContext();
4396 OpAsmParser::UnresolvedOperand input;
4397 std::string fieldName;
4399 if (parser.parseOperand(input) || parser.parseLSquare() ||
4400 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4401 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4402 parser.parseType(inputType))
4405 if (parser.resolveOperand(input, inputType, result.operands))
4408 auto enumType = type_dyn_cast<FEnumType>(inputType);
4410 return parser.emitError(parser.getNameLoc(),
4411 "input must be enum type, got ")
4413 auto fieldIndex = enumType.getElementIndex(fieldName);
4415 return parser.emitError(parser.getNameLoc(),
4416 "unknown field " + fieldName +
" in enum type ")
4419 result.addAttribute(
4423 SmallVector<Type> inferredReturnTypes;
4425 context, result.location, result.operands,
4426 result.attributes.getDictionary(context), result.getRawProperties(),
4427 result.regions, inferredReturnTypes)))
4429 result.addTypes(inferredReturnTypes);
4434 ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4435 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4437 ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4438 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4441 template <
typename OpTy>
4443 printer <<
' ' << op.getInput() <<
'[';
4444 printer.printKeywordOrString(op.getFieldName());
4446 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4447 elidedAttrs.push_back(
"fieldIndex");
4448 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4449 printer <<
" : " << op.getInput().getType();
4451 void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4452 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4454 void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4455 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4458 void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4459 printer <<
' ' << getInput() <<
'[';
4462 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4463 elidedAttrs.push_back(
"fieldIndex");
4464 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4465 printer <<
" : " << getInput().getType();
4468 template <
typename OpTy>
4470 if (op.getFieldIndex() >=
4471 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4473 return op.emitOpError(
"subfield element index is greater than the number "
4474 "of fields in the bundle type");
4477 LogicalResult SubfieldOp::verify() {
4478 return verifySubfieldLike<SubfieldOp>(*
this);
4480 LogicalResult OpenSubfieldOp::verify() {
4481 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4484 LogicalResult SubtagOp::verify() {
4485 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4486 return emitOpError(
"subfield element index is greater than the number "
4487 "of fields in the bundle type");
4497 SmallVector<Operation *, 8> worklist({op});
4501 bool constant =
true;
4507 while (constant && !(worklist.empty()))
4508 TypeSwitch<Operation *>(worklist.pop_back_val())
4509 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4510 if (
auto definingOp = op.getInput().getDefiningOp())
4511 worklist.push_back(definingOp);
4514 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4515 for (
auto &use : op.getResult().getUses())
4516 worklist.push_back(use.getOwner());
4518 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4519 .Default([&](
auto) { constant =
false; });
4528 if (
auto *op = value.getDefiningOp())
4533 LogicalResult ConstCastOp::verify() {
4535 return emitOpError() << getInput().getType()
4536 <<
" is not 'const'-castable to "
4537 << getResult().getType();
4541 FIRRTLType SubfieldOp::inferReturnType(ValueRange operands,
4542 ArrayRef<NamedAttribute> attrs,
4543 std::optional<Location> loc) {
4544 auto inType = type_cast<BundleType>(operands[0].getType());
4546 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4548 if (fieldIndex >= inType.getNumElements())
4550 "subfield element index is greater than the "
4551 "number of fields in the bundle type");
4555 return inType.getElementTypePreservingConst(fieldIndex);
4558 FIRRTLType OpenSubfieldOp::inferReturnType(ValueRange operands,
4559 ArrayRef<NamedAttribute> attrs,
4560 std::optional<Location> loc) {
4561 auto inType = type_cast<OpenBundleType>(operands[0].getType());
4563 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4565 if (fieldIndex >= inType.getNumElements())
4567 "subfield element index is greater than the "
4568 "number of fields in the bundle type");
4572 return inType.getElementTypePreservingConst(fieldIndex);
4575 bool SubfieldOp::isFieldFlipped() {
4576 BundleType bundle = getInput().getType();
4577 return bundle.getElement(getFieldIndex()).isFlip;
4579 bool OpenSubfieldOp::isFieldFlipped() {
4580 auto bundle = getInput().getType();
4581 return bundle.getElement(getFieldIndex()).isFlip;
4584 FIRRTLType SubindexOp::inferReturnType(ValueRange operands,
4585 ArrayRef<NamedAttribute> attrs,
4586 std::optional<Location> loc) {
4587 Type inType = operands[0].getType();
4589 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4591 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4592 if (fieldIdx < vectorType.getNumElements())
4593 return vectorType.getElementTypePreservingConst();
4595 "' in vector type ", inType);
4601 FIRRTLType OpenSubindexOp::inferReturnType(ValueRange operands,
4602 ArrayRef<NamedAttribute> attrs,
4603 std::optional<Location> loc) {
4604 Type inType = operands[0].getType();
4606 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4608 if (
auto vectorType = type_dyn_cast<OpenVectorType>(inType)) {
4609 if (fieldIdx < vectorType.getNumElements())
4610 return vectorType.getElementTypePreservingConst();
4612 "' in vector type ", inType);
4618 FIRRTLType SubtagOp::inferReturnType(ValueRange operands,
4619 ArrayRef<NamedAttribute> attrs,
4620 std::optional<Location> loc) {
4621 auto inType = type_cast<FEnumType>(operands[0].getType());
4623 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4625 if (fieldIndex >= inType.getNumElements())
4627 "subtag element index is greater than the "
4628 "number of fields in the enum type");
4632 auto elementType = inType.getElement(fieldIndex).type;
4636 FIRRTLType SubaccessOp::inferReturnType(ValueRange operands,
4637 ArrayRef<NamedAttribute> attrs,
4638 std::optional<Location> loc) {
4639 auto inType = operands[0].getType();
4640 auto indexType = operands[1].getType();
4642 if (!type_isa<UIntType>(indexType))
4646 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4648 return vectorType.getElementTypePreservingConst();
4649 return vectorType.getElementType().getAllConstDroppedType();
4656 FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4657 ArrayRef<NamedAttribute> attrs,
4658 std::optional<Location> loc) {
4659 auto inType = type_cast<FEnumType>(operands[0].getType());
4660 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4664 ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4665 OpAsmParser::UnresolvedOperand index;
4666 SmallVector<OpAsmParser::UnresolvedOperand, 16>
inputs;
4667 Type indexType, elemType;
4669 if (parser.parseOperand(index) || parser.parseComma() ||
4670 parser.parseOperandList(
inputs) ||
4671 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4672 parser.parseType(indexType) || parser.parseComma() ||
4673 parser.parseType(elemType))
4676 if (parser.resolveOperand(index, indexType, result.operands))
4679 result.addTypes(elemType);
4681 return parser.resolveOperands(
inputs, elemType, result.operands);
4684 void MultibitMuxOp::print(OpAsmPrinter &p) {
4685 p <<
" " << getIndex() <<
", ";
4686 p.printOperands(getInputs());
4687 p.printOptionalAttrDict((*this)->getAttrs());
4688 p <<
" : " << getIndex().getType() <<
", " << getType();
4691 FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4692 ArrayRef<NamedAttribute> attrs,
4693 std::optional<Location> loc) {
4694 if (operands.size() < 2)
4698 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4699 return operands[1].getType() == op.getType();
4703 return type_cast<FIRRTLType>(operands[1].getType());
4711 MLIRContext *context, std::optional<mlir::Location> location,
4712 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4713 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4714 auto type = inferReturnType(operands, attributes.getValue(), location);
4717 inferredReturnTypes.push_back(type);
4721 Type ObjectSubfieldOp::inferReturnType(ValueRange operands,
4722 ArrayRef<NamedAttribute> attrs,
4723 std::optional<Location> loc) {
4724 auto classType = dyn_cast<ClassType>(operands[0].getType());
4728 auto index = getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4729 if (classType.getNumElements() <= index)
4731 "number of fields in the object");
4733 return classType.getElement(index).type;
4736 void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4737 auto input = getInput();
4738 auto classType = input.getType();
4739 p <<
' ' << input <<
"[";
4740 p.printKeywordOrString(classType.getElement(getIndex()).name);
4742 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4743 p <<
" : " << classType;
4746 ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4747 OperationState &result) {
4748 auto *context = parser.getContext();
4750 OpAsmParser::UnresolvedOperand input;
4751 std::string fieldName;
4752 ClassType inputType;
4753 if (parser.parseOperand(input) || parser.parseLSquare() ||
4754 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4755 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4756 parser.parseType(inputType) ||
4757 parser.resolveOperand(input, inputType, result.operands))
4760 auto index = inputType.getElementIndex(fieldName);
4762 return parser.emitError(parser.getNameLoc(),
4763 "unknown field " + fieldName +
" in class type ")
4765 result.addAttribute(
"index",
4768 SmallVector<Type> inferredReturnTypes;
4770 result.attributes.getDictionary(context),
4771 result.getRawProperties(), result.regions,
4772 inferredReturnTypes)))
4774 result.addTypes(inferredReturnTypes);
4791 int32_t &rhsWidth,
bool &isConstResult,
4792 std::optional<Location> loc) {
4794 auto lhsi = type_dyn_cast<IntType>(lhs);
4795 auto rhsi = type_dyn_cast<IntType>(rhs);
4796 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4799 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4801 else if (!lhsi && rhsi)
4802 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4804 else if (!lhsi && !rhsi)
4805 mlir::emitError(*loc,
"operands must be integer types, not ")
4806 << lhs <<
" and " << rhs;
4808 mlir::emitError(*loc,
"operand signedness must match");
4813 lhsWidth = lhsi.getWidthOrSentinel();
4814 rhsWidth = rhsi.getWidthOrSentinel();
4815 isConstResult = lhsi.isConst() && rhsi.isConst();
4820 assert(op->getNumOperands() == 2 &&
4821 "SameOperandsIntTypeKind on non-binary op");
4822 int32_t lhsWidth, rhsWidth;
4825 op->getOperand(1).getType(), lhsWidth,
4826 rhsWidth, isConstResult, op->getLoc()));
4830 ArrayRef<NamedAttribute> attrs,
4832 if (operands.size() != 2 || !attrs.empty()) {
4833 mlir::emitError(loc,
"operation requires two operands and no constants");
4840 std::optional<Location> loc) {
4841 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4842 bool isConstResult =
false;
4846 if (lhsWidth != -1 && rhsWidth != -1)
4847 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
4848 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4853 std::optional<Location> loc) {
4854 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4855 bool isConstResult =
false;
4859 if (lhsWidth != -1 && rhsWidth != -1)
4860 resultWidth = lhsWidth + rhsWidth;
4862 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4867 std::optional<Location> loc) {
4868 int32_t lhsWidth, rhsWidth;
4869 bool isConstResult =
false;
4874 if (type_isa<UIntType>(lhs))
4875 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
4878 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
4879 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
4883 std::optional<Location> loc) {
4884 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4885 bool isConstResult =
false;
4889 if (lhsWidth != -1 && rhsWidth != -1)
4890 resultWidth = std::min(lhsWidth, rhsWidth);
4891 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4896 std::optional<Location> loc) {
4897 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4898 bool isConstResult =
false;
4902 if (lhsWidth != -1 && rhsWidth != -1) {
4903 resultWidth = std::max(lhsWidth, rhsWidth);
4904 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
4907 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
4911 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
4915 std::optional<Location> loc) {
4916 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
4919 auto lhsVec = type_cast<FVectorType>(lhs);
4920 auto rhsVec = type_cast<FVectorType>(rhs);
4922 if (lhsVec.getNumElements() != rhsVec.getNumElements())
4927 rhsVec.getElementTypePreservingConst(), loc);
4930 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
4932 lhsVec.isConst() && rhsVec.isConst() &&
4933 elemBaseType.isConst());
4937 std::optional<Location> loc) {
4942 std::optional<Location> loc) {
4943 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4944 bool isConstResult =
false;
4948 if (lhsWidth != -1 && rhsWidth != -1)
4949 resultWidth = lhsWidth + rhsWidth;
4950 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
4954 std::optional<Location> loc) {
4955 auto lhsi = type_dyn_cast<IntType>(lhs);
4956 auto rhsui = type_dyn_cast<UIntType>(rhs);
4957 if (!rhsui || !lhsi)
4959 loc,
"first operand should be integer, second unsigned int");
4963 auto width = lhsi.getWidthOrSentinel();
4964 if (
width == -1 || !rhsui.getWidth().has_value()) {
4967 auto amount = *rhsui.getWidth();
4970 "shift amount too large: second operand of "
4971 "dshl is wider than 31 bits");
4972 int64_t newWidth = (int64_t)
width + ((int64_t)1 << amount) - 1;
4973 if (newWidth > INT32_MAX)
4975 loc,
"shift amount too large: first operand shifted by maximum "
4976 "amount exceeds maximum width");
4980 lhsi.isConst() && rhsui.isConst());
4984 std::optional<Location> loc) {
4985 auto lhsi = type_dyn_cast<IntType>(lhs);
4986 auto rhsu = type_dyn_cast<UIntType>(rhs);
4989 loc,
"first operand should be integer, second unsigned int");
4990 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
4994 std::optional<Location> loc) {
4995 auto lhsi = type_dyn_cast<IntType>(lhs);
4996 auto rhsu = type_dyn_cast<UIntType>(rhs);
4999 loc,
"first operand should be integer, second unsigned int");
5000 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5008 ArrayRef<NamedAttribute> attrs,
5010 if (operands.size() != 1 || !attrs.empty()) {
5011 mlir::emitError(loc,
"operation requires one operand and no constants");
5018 SizeOfIntrinsicOp::inferUnaryReturnType(
FIRRTLType input,
5019 std::optional<Location> loc) {
5024 std::optional<Location> loc) {
5025 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5028 int32_t
width = base.getBitWidthOrSentinel();
5035 std::optional<Location> loc) {
5036 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5039 int32_t
width = base.getBitWidthOrSentinel();
5046 AsAsyncResetPrimOp::inferUnaryReturnType(
FIRRTLType input,
5047 std::optional<Location> loc) {
5048 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5051 "operand must be single bit scalar base type");
5052 int32_t
width = base.getBitWidthOrSentinel();
5059 std::optional<Location> loc) {
5064 std::optional<Location> loc) {
5065 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5066 auto width = uiType.getWidthOrSentinel();
5072 if (type_isa<SIntType>(input))
5079 std::optional<Location> loc) {
5080 auto inputi = type_dyn_cast<IntType>(input);
5083 int32_t
width = inputi.getWidthOrSentinel();
5090 std::optional<Location> loc) {
5091 auto inputi = type_dyn_cast<IntType>(input);
5094 if (isa<UIntType>(inputi))
5096 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5101 std::optional<Location> loc) {
5109 LogicalResult BitsPrimOp::validateArguments(ValueRange operands,
5110 ArrayRef<NamedAttribute> attrs,
5112 if (operands.size() != 1 || attrs.size() != 2) {
5113 mlir::emitError(loc,
"operation requires one operand and two constants");
5119 FIRRTLType BitsPrimOp::inferReturnType(ValueRange operands,
5120 ArrayRef<NamedAttribute> attrs,
5121 std::optional<Location> loc) {
5122 auto input = operands[0].getType();
5123 auto high = getAttr<IntegerAttr>(attrs,
"hi").getValue().getSExtValue();
5124 auto low = getAttr<IntegerAttr>(attrs,
"lo").getValue().getSExtValue();
5126 auto inputi = type_dyn_cast<IntType>(input);
5129 loc,
"input type should be the int type but got ", input);
5134 loc,
"high must be equal or greater than low, but got high = ", high,
5142 int32_t
width = inputi.getWidthOrSentinel();
5146 "high must be smaller than the width of input, but got high = ", high,
5147 ", width = ",
width);
5153 ArrayRef<NamedAttribute> attrs,
5155 if (operands.size() != 1 || attrs.size() != 1) {
5156 mlir::emitError(loc,
"operation requires one operand and one constant");
5162 FIRRTLType HeadPrimOp::inferReturnType(ValueRange operands,
5163 ArrayRef<NamedAttribute> attrs,
5164 std::optional<Location> loc) {
5165 auto input = operands[0].getType();
5166 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5168 auto inputi = type_dyn_cast<IntType>(input);
5169 if (amount < 0 || !inputi)
5171 loc,
"operand must have integer type and amount must be >= 0");
5173 int32_t
width = inputi.getWidthOrSentinel();
5180 LogicalResult MuxPrimOp::validateArguments(ValueRange operands,
5181 ArrayRef<NamedAttribute> attrs,
5183 if (operands.size() != 3 || attrs.size() != 0) {
5184 mlir::emitError(loc,
"operation requires three operands and no constants");
5202 bool isConstCondition,
5203 std::optional<Location> loc) {
5209 if (high.getTypeID() != low.getTypeID())
5210 return emitInferRetTypeError<FIRRTLBaseType>(
5211 loc,
"incompatible mux operand types, true value type: ", high,
5212 ", false value type: ", low);
5214 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5219 if (type_isa<IntType>(low)) {
5224 if (highWidth == -1)
5226 return (lowWidth > highWidth ? low : high).
getConstType(outerTypeIsConst);
5230 auto highVector = type_dyn_cast<FVectorType>(high);
5231 auto lowVector = type_dyn_cast<FVectorType>(low);
5232 if (highVector && lowVector &&
5233 highVector.getNumElements() == lowVector.getNumElements()) {
5235 lowVector.getElementTypePreservingConst(),
5236 isConstCondition, loc);
5244 auto highBundle = type_dyn_cast<BundleType>(high);
5245 auto lowBundle = type_dyn_cast<BundleType>(low);
5246 if (highBundle && lowBundle) {
5247 auto highElements = highBundle.getElements();
5248 auto lowElements = lowBundle.getElements();
5251 SmallVector<BundleType::BundleElement> newElements;
5253 bool failed =
false;
5255 if (highElements[i].name != lowElements[i].name ||
5256 highElements[i].isFlip != lowElements[i].isFlip) {
5260 auto element = highElements[i];
5262 highBundle.getElementTypePreservingConst(i),
5263 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5266 newElements.push_back(element);
5269 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5271 return emitInferRetTypeError<FIRRTLBaseType>(
5272 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5273 ", false value type: ", low);
5278 return emitInferRetTypeError<FIRRTLBaseType>(
5279 loc,
"invalid mux operand types, true value type: ", high,
5280 ", false value type: ", low);
5283 FIRRTLType MuxPrimOp::inferReturnType(ValueRange operands,
5284 ArrayRef<NamedAttribute> attrs,
5285 std::optional<Location> loc) {
5286 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5287 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5288 if (!highType || !lowType)
5294 FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5295 ArrayRef<NamedAttribute> attrs,
5296 std::optional<Location> loc) {
5297 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5298 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5299 if (!highType || !lowType)
5305 FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5306 ArrayRef<NamedAttribute> attrs,
5307 std::optional<Location> loc) {
5308 SmallVector<FIRRTLBaseType> types;
5310 for (
unsigned i = 1; i < 5; i++) {
5311 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5316 isConst(operands[0].getType()), loc);
5320 result = types.back();
5326 FIRRTLType PadPrimOp::inferReturnType(ValueRange operands,
5327 ArrayRef<NamedAttribute> attrs,
5328 std::optional<Location> loc) {
5329 auto input = operands[0].getType();
5330 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5332 auto inputi = type_dyn_cast<IntType>(input);
5333 if (amount < 0 || !inputi)
5335 loc,
"pad input must be integer and amount must be >= 0");
5337 int32_t
width = inputi.getWidthOrSentinel();
5346 FIRRTLType ShlPrimOp::inferReturnType(ValueRange operands,
5347 ArrayRef<NamedAttribute> attrs,
5348 std::optional<Location> loc) {
5349 auto input = operands[0].getType();
5350 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5352 auto inputi = type_dyn_cast<IntType>(input);
5353 if (amount < 0 || !inputi)
5355 loc,
"shl input must be integer and amount must be >= 0");
5357 int32_t
width = inputi.getWidthOrSentinel();
5365 FIRRTLType ShrPrimOp::inferReturnType(ValueRange operands,
5366 ArrayRef<NamedAttribute> attrs,
5367 std::optional<Location> loc) {
5368 auto input = operands[0].getType();
5369 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5371 auto inputi = type_dyn_cast<IntType>(input);
5372 if (amount < 0 || !inputi)
5374 loc,
"shr input must be integer and amount must be >= 0");
5376 int32_t
width = inputi.getWidthOrSentinel();
5379 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5380 width = std::max<int32_t>(minWidth,
width - amount);
5387 FIRRTLType TailPrimOp::inferReturnType(ValueRange operands,
5388 ArrayRef<NamedAttribute> attrs,
5389 std::optional<Location> loc) {
5390 auto input = operands[0].getType();
5391 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5393 auto inputi = type_dyn_cast<IntType>(input);
5394 if (amount < 0 || !inputi)
5396 loc,
"tail input must be integer and amount must be >= 0");
5398 int32_t
width = inputi.getWidthOrSentinel();
5402 loc,
"amount must be less than or equal operand width");
5414 function_ref<
void(Value, StringRef)> setNameFn) {
5418 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5419 auto name = getText();
5421 if (name.starts_with(
"`"))
5422 name = name.drop_front();
5423 name = name.take_while(isOkCharacter);
5425 setNameFn(getResult(), name);
5433 function_ref<
void(Value, StringRef)> setNameFn) {
5437 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5438 auto name = getText();
5440 if (name.starts_with(
"`"))
5441 name = name.drop_front();
5442 name = name.take_while(isOkCharacter);
5444 setNameFn(getResult(), name);
5451 LogicalResult HWStructCastOp::verify() {
5453 BundleType bundleType;
5454 hw::StructType structType;
5455 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5456 structType = getType().dyn_cast<hw::StructType>();
5458 return emitError(
"result type must be a struct");
5459 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5460 structType = getOperand().getType().dyn_cast<hw::StructType>();
5462 return emitError(
"operand type must be a struct");
5464 return emitError(
"either source or result type must be a bundle type");
5467 auto firFields = bundleType.getElements();
5468 auto hwFields = structType.getElements();
5469 if (firFields.size() != hwFields.size())
5470 return emitError(
"bundle and struct have different number of fields");
5472 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5473 if (firFields[findex].name.getValue() != hwFields[findex].name)
5474 return emitError(
"field names don't match '")
5475 << firFields[findex].name.getValue() <<
"', '"
5476 << hwFields[findex].name.getValue() <<
"'";
5480 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5481 return emitError(
"size of field '")
5482 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5489 LogicalResult BitCastOp::verify() {
5490 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5492 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5494 if (*inTypeBits == *resTypeBits) {
5497 return emitError(
"cannot cast non-'const' input type ")
5498 << getOperand().getType() <<
" to 'const' result type "
5502 return emitError(
"the bitwidth of input (")
5503 << *inTypeBits <<
") and result (" << *resTypeBits
5506 if (!inTypeBits.has_value())
5507 return emitError(
"bitwidth cannot be determined for input operand type ")
5508 << getInput().getType();
5509 return emitError(
"bitwidth cannot be determined for result type ")
5520 NamedAttrList &resultAttrs) {
5521 auto result = parser.parseOptionalAttrDict(resultAttrs);
5522 if (!resultAttrs.get(
"annotations"))
5523 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5529 DictionaryAttr attr,
5530 ArrayRef<StringRef> extraElides = {}) {
5531 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5533 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5534 elidedAttrs.push_back(
"annotations");
5536 elidedAttrs.push_back(
"nameKind");
5538 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5544 NamedAttrList &resultAttrs) {
5547 if (!resultAttrs.get(
"portAnnotations")) {
5548 SmallVector<Attribute, 16> portAnnotations(
5549 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5550 resultAttrs.append(
"portAnnotations",
5551 parser.getBuilder().getArrayAttr(portAnnotations));
5558 DictionaryAttr attr,
5559 ArrayRef<StringRef> extraElides = {}) {
5560 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5562 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5563 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5564 elidedAttrs.push_back(
"portAnnotations");
5573 firrtl::NameKindEnumAttr &result) {
5576 if (!parser.parseOptionalKeyword(&keyword,
5577 {
"interesting_name",
"droppable_name"})) {
5578 auto kind = symbolizeNameKindEnum(keyword);
5590 firrtl::NameKindEnumAttr attr,
5591 ArrayRef<StringRef> extraElides = {}) {
5592 if (attr.getValue() != NameKindEnum::DroppableName)
5593 p <<
" " << stringifyNameKindEnum(attr.getValue());
5601 NamedAttrList &resultAttrs) {
5609 DictionaryAttr attrs) {
5610 SmallVector<StringRef, 4> elides;
5612 elides.push_back(Forceable::getForceableAttrName());
5621 static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5626 static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5637 if (ClassType::parseInterface(parser, type))
5644 type.printInterface(p);
5652 NamedAttrList &resultAttrs) {
5653 auto result = p.parseOptionalAttrDict(resultAttrs);
5654 if (!resultAttrs.get(
"name"))
5655 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5661 DictionaryAttr attr,
5662 ArrayRef<StringRef> extraElides = {}) {
5663 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5664 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5665 elides.push_back(
"name");
5667 p.printOptionalAttrDict(op->getAttrs(), elides);
5671 NamedAttrList &resultAttrs) {
5676 DictionaryAttr attr) {
5685 DictionaryAttr attr) {
5694 DictionaryAttr attr) {
5706 if (op->getNumResults() == 1)
5707 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5708 setNameFn(op->getResult(0), nameAttr.getValue());
5932 FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
5933 ArrayRef<NamedAttribute> attrs,
5934 std::optional<Location> loc) {
5935 Type inType = operands[0].getType();
5936 auto inRefType = type_dyn_cast<RefType>(inType);
5939 loc,
"ref.resolve operand must be ref type, not ", inType);
5940 return inRefType.getType();
5943 FIRRTLType RefSendOp::inferReturnType(ValueRange operands,
5944 ArrayRef<NamedAttribute> attrs,
5945 std::optional<Location> loc) {
5946 Type inType = operands[0].getType();
5947 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
5950 loc,
"ref.send operand must be base type, not ", inType);
5954 FIRRTLType RefSubOp::inferReturnType(ValueRange operands,
5955 ArrayRef<NamedAttribute> attrs,
5956 std::optional<Location> loc) {
5957 auto refType = type_dyn_cast<RefType>(operands[0].getType());
5960 auto inType = refType.getType();
5962 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
5968 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5969 if (fieldIdx < vectorType.getNumElements())
5971 vectorType.getElementType().getConstType(
5972 vectorType.isConst() || vectorType.getElementType().isConst()),
5973 refType.getForceable(), refType.getLayer());
5975 "' in RefType of vector type ", refType);
5977 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
5978 if (fieldIdx >= bundleType.getNumElements()) {
5980 "subfield element index is greater than "
5981 "the number of fields in the bundle type");
5983 return RefType::get(bundleType.getElement(fieldIdx).type.getConstType(
5984 bundleType.isConst() ||
5985 bundleType.getElement(fieldIdx).type.isConst()),
5986 refType.getForceable(), refType.getLayer());
5990 loc,
"ref.sub op requires a RefType of vector or bundle base type");
5993 LogicalResult RefCastOp::verify() {
5996 SmallVector<SymbolRefAttr> missingLayers;
5999 emitOpError(
"cannot discard layer requirements of input reference");
6000 auto ¬e = diag.attachNote();
6001 note <<
"discarding layer requirements: ";
6002 llvm::interleaveComma(missingLayers, note);
6008 LogicalResult RefResolveOp::verify() {
6011 SmallVector<SymbolRefAttr> missingLayers;
6014 emitOpError(
"ambient layers are insufficient to resolve reference");
6015 auto ¬e = diag.attachNote();
6016 note <<
"missing layer requirements: ";
6017 interleaveComma(missingLayers, note);
6023 LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
6024 auto targetRef = getTarget();
6025 if (targetRef.getModule() !=
6026 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6027 return emitOpError() <<
"has non-local target";
6029 auto target = ns.lookup(targetRef);
6031 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6033 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6038 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6039 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6040 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6041 << fType <<
" instead of expected " << getType().getType();
6042 diag.attachNote(loc) <<
"target resolves here";
6047 if (target.isPort()) {
6048 auto mod = cast<FModuleLike>(target.getOp());
6049 return checkFinalType(mod.getPortType(target.getPort()),
6050 mod.getPortLocation(target.getPort()));
6052 hw::InnerSymbolOpInterface symOp =
6053 cast<hw::InnerSymbolOpInterface>(target.getOp());
6054 if (!symOp.getTargetResult())
6055 return emitOpError(
"has target that cannot be probed")
6056 .attachNote(symOp.getLoc())
6057 .append(
"target resolves here");
6059 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6060 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6061 return emitOpError(
"is not dominated by target")
6062 .attachNote(symOp.getLoc())
6063 .append(
"target here");
6064 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6071 LogicalResult LayerBlockOp::verify() {
6072 auto layerName = getLayerName();
6073 auto *parentOp = (*this)->getParentOp();
6077 auto nestedReferences = layerName.getNestedReferences();
6078 if (nestedReferences.empty()) {
6079 if (!isa<FModuleOp>(parentOp)) {
6080 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6081 "not have a 'firrtl.module' op as a parent";
6082 return diag.attachNote(parentOp->getLoc())
6083 <<
"illegal parent op defined here";
6086 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6087 if (!parentLayerBlock) {
6088 auto diag = emitOpError()
6089 <<
"has a nested layer symbol, but does not have a '"
6090 << getOperationName() <<
"' op as a parent'";
6091 return diag.attachNote(parentOp->getLoc())
6092 <<
"illegal parent op defined here";
6094 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6095 if (parentLayerBlockName.getRootReference() !=
6096 layerName.getRootReference() ||
6097 parentLayerBlockName.getNestedReferences() !=
6098 layerName.getNestedReferences().drop_back()) {
6099 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6100 return diag.attachNote(parentLayerBlock->getLoc())
6101 <<
"illegal parent layer block defined here";
6106 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6107 [&](Operation *op) -> WalkResult {
6109 if (isa<LayerBlockOp>(op))
6110 return WalkResult::skip();
6114 for (
auto operand : op->getOperands()) {
6116 if (
auto *definingOp = operand.getDefiningOp())
6117 if (getOperation()->isAncestor(definingOp))
6120 auto type = operand.getType();
6123 if (isa<PropertyType>(type)) {
6124 auto diag = emitOpError() <<
"captures a property operand";
6125 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6126 diag.attachNote(op->getLoc()) <<
"operand is used here";
6127 return WalkResult::interrupt();
6131 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type)) {
6132 if (!baseType.isPassive()) {
6133 auto diag = emitOpError()
6134 <<
"captures an operand which is not a passive type";
6135 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6136 diag.attachNote(op->getLoc()) <<
"operand is used here";
6137 return WalkResult::interrupt();
6143 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6145 if (isa<RefDefineOp>(
connect))
6146 return WalkResult::advance();
6150 if (
auto *destOp = dest.getDefiningOp())
6152 return WalkResult::advance();
6156 <<
"connects to a destination which is defined outside its "
6157 "enclosing layer block";
6158 diag.attachNote(getLoc()) <<
"enclosing layer block is defined here";
6159 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6160 return WalkResult::interrupt();
6163 return WalkResult::advance();
6166 return failure(result.wasInterrupted());
6170 LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6172 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6174 return emitOpError(
"invalid symbol reference");
6185 #define GET_OP_CLASSES
6186 #include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
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)
Print a list of module ports in the following form: in x: !firrtl.uint<1> [{class = "DontTouch}],...
static LogicalResult verifyProbeType(RefType refType, Location loc, CircuitOp circuitOp, SymbolTableCollection &symbolTable, Twine start)
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
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 eraseInternalPaths(T op, const llvm::BitVector &portIndices)
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 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 ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
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 parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs)
Parse a list of module ports.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static void printNameKind(OpAsmPrinter &p, Operation *op, firrtl::NameKindEnumAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
SmallSet< SymbolRefAttr, 4, CompareSymbolRefAttr > LayerSet
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static LogicalResult verifyInternalPaths(FModuleLike op, std::optional<::mlir::ArrayAttr > internalPaths)
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
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.
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo >> ports, bool supportsInternalPaths=false)
Inserts the given ports.
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)
static SmallVector< PortInfo > getPortImpl(FModuleLike module)
constexpr const char * toString(Flow flow)
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 SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
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.
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static Attribute maybeGetAttr(ArrayRef< NamedAttribute > attrs, StringRef name)
Get an attribute by name from a list of named attributes.
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static Attribute getAttr(ArrayRef< NamedAttribute > attrs, StringRef name)
Get an attribute by name from a list of named attributes.
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers, bool withAnnotations, bool withLayers)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
static PortInfo getPort(ModuleTy &mod, size_t idx)
static InstancePath empty
static bool isAncestor(Operation *op, Value value)
FirMemory getSummary(MemOp op)
llvm::SmallVector< StringAttr > inputs
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
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 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...
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
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...
FIRRTLBaseType getConstType(bool isConst)
Return a 'const' or non-'const' version of this type.
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
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.
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
def connect(destination, source)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
IntegerAttr packAttribute(MLIRContext *context, size_t nIns, size_t nOuts)
Returns an IntegerAttr containing the packed representation of the direction counts.
Direction
The direction of a Component or Cell port.
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
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.
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.
LogicalResult validateBinaryOpArguments(ValueRange operands, ArrayRef< NamedAttribute > attrs, Location loc)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
LogicalResult inferReturnTypes(MLIRContext *context, std::optional< Location > loc, ValueRange operands, DictionaryAttr attrs, mlir::OpaqueProperties properties, mlir::RegionRange regions, SmallVectorImpl< Type > &results, llvm::function_ref< FIRRTLType(ValueRange, ArrayRef< NamedAttribute >, std::optional< Location >)> callback)
LogicalResult validateUnaryOpArguments(ValueRange operands, ArrayRef< NamedAttribute > attrs, 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 validateOneOperandOneConst(ValueRange operands, ArrayRef< NamedAttribute > attrs, 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.
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.
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)
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.
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.
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.
void getAsmResultNames(OpAsmSetValueNameFn setNameFn, StringRef instanceName, ArrayAttr resultNames, ValueRange results)
Suggest a name for each result value based on the saved result names attribute.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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 inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
This holds the name, type, direction of a module's ports.