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; });
116 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
117 MemOp::computeDataFlow() {
120 if (getReadLatency() > 0)
122 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
124 for (
auto memPort : getResults())
125 if (
auto type = type_dyn_cast<BundleType>(memPort.getType())) {
130 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
131 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
133 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
134 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
141 constexpr
unsigned int addr = 1 << 0;
142 constexpr
unsigned int en = 1 << 1;
143 constexpr
unsigned int clk = 1 << 2;
144 constexpr
unsigned int data = 1 << 3;
145 constexpr
unsigned int mask = 1 << 4;
146 constexpr
unsigned int rdata = 1 << 5;
147 constexpr
unsigned int wdata = 1 << 6;
148 constexpr
unsigned int wmask = 1 << 7;
149 constexpr
unsigned int wmode = 1 << 8;
150 constexpr
unsigned int def = 1 << 9;
152 auto portType = type_dyn_cast<BundleType>(type);
154 return MemOp::PortKind::Debug;
157 for (
auto elem : portType.getElements()) {
158 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
164 .Case(
"rdata",
rdata)
165 .Case(
"wdata",
wdata)
166 .Case(
"wmask",
wmask)
167 .Case(
"wmode",
wmode)
171 return MemOp::PortKind::Read;
173 return MemOp::PortKind::Write;
175 return MemOp::PortKind::ReadWrite;
176 return MemOp::PortKind::Debug;
191 llvm_unreachable(
"Unsupported Flow type.");
199 return "source flow";
203 return "duplex flow";
206 llvm_unreachable(
"Unsupported Flow type.");
211 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
212 auto *op = val.getParentBlock()->getParentOp();
213 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
214 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
218 return accumulatedFlow;
221 Operation *op = val.getDefiningOp();
223 return TypeSwitch<Operation *, Flow>(op)
224 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
225 return foldFlow(op.getInput(), op.isFieldFlipped()
229 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
230 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
232 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
234 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
235 auto resultNo = cast<OpResult>(val).getResultNumber();
237 return accumulatedFlow;
240 .Case<MemOp>([&](
auto op) {
242 if (type_isa<RefType>(val.getType()))
246 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
247 auto input = op.getInput();
248 auto *inputOp = input.getDefiningOp();
251 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
252 auto classType = input.getType();
253 auto direction = classType.getElement(op.getIndex()).direction;
265 auto classType = input.getType();
266 auto direction = classType.getElement(op.getIndex()).direction;
270 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
272 input = op.getInput();
273 inputOp = input.getDefiningOp();
277 return accumulatedFlow;
281 .Default([&](
auto) {
return accumulatedFlow; });
287 Operation *op = val.getDefiningOp();
291 return TypeSwitch<Operation *, DeclKind>(op)
293 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
299 if (
auto module = dyn_cast<FModuleLike>(op))
300 return module.getNumPorts();
301 return op->getNumResults();
315 if (
auto *op = value.getDefiningOp())
317 auto arg = dyn_cast<BlockArgument>(value);
318 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
319 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
330 auto *block = ®ion.front();
333 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
335 if (!argAttr || argAttr.size() != block->getNumArguments())
338 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
339 auto str = cast<StringAttr>(argAttr[i]).getValue();
341 setNameFn(block->getArgument(i), str);
347 firrtl::NameKindEnumAttr &result);
354 struct CompareSymbolRefAttr {
356 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
357 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
362 auto lhsNested = lhs.getNestedReferences();
363 auto rhsNested = rhs.getNestedReferences();
364 auto lhsNestedSize = lhsNested.size();
365 auto rhsNestedSize = rhsNested.size();
366 auto e = std::min(lhsNestedSize, rhsNestedSize);
367 for (
unsigned i = 0; i < e; ++i) {
368 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].
getAttr());
374 return lhsNestedSize < rhsNestedSize;
386 for (; op !=
nullptr; op = op->getParentOp()) {
387 if (
auto module = dyn_cast<FModuleLike>(op)) {
388 auto layers = module.getLayersAttr().getAsRange<SymbolRefAttr>();
389 result.insert(layers.begin(), layers.end());
392 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
393 result.insert(layerblock.getLayerName());
411 if (
auto type = dyn_cast<RefType>(value.getType()))
412 if (
auto layer = type.getLayer())
413 result.insert(type.getLayer());
422 mlir::SymbolRefAttr dstLayer) {
432 if (srcLayer.getRootReference() != dstLayer.getRootReference())
435 auto srcNames = srcLayer.getNestedReferences();
436 auto dstNames = dstLayer.getNestedReferences();
437 if (dstNames.size() < srcNames.size())
440 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
441 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
448 if (dstLayers.contains(srcLayer))
453 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
462 SmallVectorImpl<SymbolRefAttr> &missing) {
463 for (
auto srcLayer : src)
465 missing.push_back(srcLayer);
467 llvm::sort(missing, CompareSymbolRefAttr());
468 return missing.empty();
475 void CircuitOp::build(OpBuilder &builder, OperationState &result,
476 StringAttr name, ArrayAttr annotations) {
478 result.addAttribute(builder.getStringAttr(
"name"), name);
481 annotations = builder.getArrayAttr({});
482 result.addAttribute(
"annotations", annotations);
485 Region *bodyRegion = result.addRegion();
487 bodyRegion->push_back(body);
491 NamedAttrList &resultAttrs) {
492 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
493 if (!resultAttrs.get(
"annotations"))
494 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
500 DictionaryAttr attr) {
502 SmallVector<StringRef> elidedAttrs = {
"name"};
504 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
505 if (annotationsAttr.empty())
506 elidedAttrs.push_back(
"annotations");
508 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
511 LogicalResult CircuitOp::verifyRegions() {
516 emitOpError(
"must have a non-empty name");
520 mlir::SymbolTable symtbl(getOperation());
522 if (!symtbl.lookup(
main))
523 return emitOpError().append(
"Module with same name as circuit not found");
528 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
530 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
534 auto defname = extModule.getDefnameAttr();
540 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
541 return extModule.emitOpError()
542 .append(
"attribute 'defname' with value ", defname,
543 " conflicts with the name of another module in the circuit")
544 .attachNote(collidingModule.getLoc())
545 .append(
"previous module declared here");
553 FExtModuleOp collidingExtModule;
554 if (
auto &value = defnameMap[defname]) {
555 collidingExtModule = value;
556 if (!value.getParameters().empty() && extModule.getParameters().empty())
566 SmallVector<PortInfo> ports = extModule.getPorts();
567 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
569 if (ports.size() != collidingPorts.size())
570 return extModule.emitOpError()
571 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
572 " ports which is different from a previously defined "
573 "extmodule with the same 'defname' which has ",
574 collidingPorts.size(),
" ports")
575 .attachNote(collidingExtModule.getLoc())
576 .append(
"previous extmodule definition occurred here");
582 for (
auto p : llvm::zip(ports, collidingPorts)) {
583 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
584 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
587 return extModule.emitOpError()
588 .append(
"with 'defname' attribute ", defname,
589 " has a port with name ", aName,
590 " which does not match the name of the port in the same "
591 "position of a previously defined extmodule with the same "
592 "'defname', expected port to have name ",
594 .attachNote(collidingExtModule.getLoc())
595 .append(
"previous extmodule definition occurred here");
597 if (!extModule.getParameters().empty() ||
598 !collidingExtModule.getParameters().empty()) {
600 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
601 aType = base.getWidthlessType();
602 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
603 bType = base.getWidthlessType();
606 return extModule.emitOpError()
607 .append(
"with 'defname' attribute ", defname,
608 " has a port with name ", aName,
609 " which has a different type ", aType,
610 " which does not match the type of the port in the same "
611 "position of a previously defined extmodule with the same "
612 "'defname', expected port to have type ",
614 .attachNote(collidingExtModule.getLoc())
615 .append(
"previous extmodule definition occurred here");
622 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
623 if (verifyExtModule(extModule).failed())
638 SmallVector<PortInfo> results;
639 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
640 results.push_back({module.getPortNameAttr(i), module.getPortType(i),
641 module.getPortDirection(i), module.getPortSymbolAttr(i),
642 module.getPortLocation(i),
661 assert(0 &&
"invalid direction");
666 SmallVector<hw::PortInfo> results;
668 hw::HWModuleLike::getPortSymbolAttrName());
670 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
671 auto sym = module.getPortSymbolAttr(i);
673 {{module.getPortNameAttr(i), module.getPortType(i),
674 dirFtoH(module.getPortDirection(i))},
678 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
680 module.getPortLocation(i)});
702 return {{module.getPortNameAttr(idx), module.getPortType(idx),
703 dirFtoH(module.getPortDirection(idx))},
707 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
708 StringAttr::get(module.getContext(),
709 hw::HWModuleLike::getPortSymbolAttrName()),
710 module.getPortSymbolAttr(idx)}}),
711 module.getPortLocation(idx)};
731 BlockArgument FModuleOp::getArgument(
size_t portNumber) {
739 ArrayRef<std::pair<unsigned, PortInfo>> ports,
740 bool supportsInternalPaths =
false) {
743 unsigned oldNumArgs = op.getNumPorts();
744 unsigned newNumArgs = oldNumArgs + ports.size();
747 auto existingDirections = op.getPortDirectionsAttr();
748 ArrayRef<Attribute> existingNames = op.getPortNames();
749 ArrayRef<Attribute> existingTypes = op.getPortTypes();
750 ArrayRef<Attribute> existingLocs = op.getPortLocations();
751 assert(existingDirections.size() == oldNumArgs);
752 assert(existingNames.size() == oldNumArgs);
753 assert(existingTypes.size() == oldNumArgs);
754 assert(existingLocs.size() == oldNumArgs);
755 SmallVector<Attribute> internalPaths;
757 if (supportsInternalPaths) {
758 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
759 llvm::append_range(internalPaths, internalPathsAttr);
761 internalPaths.resize(oldNumArgs, emptyInternalPath);
762 assert(internalPaths.size() == oldNumArgs);
765 SmallVector<bool> newDirections;
766 SmallVector<Attribute> newNames, newTypes, newAnnos, newSyms, newLocs,
768 newDirections.reserve(newNumArgs);
769 newNames.reserve(newNumArgs);
770 newTypes.reserve(newNumArgs);
771 newAnnos.reserve(newNumArgs);
772 newSyms.reserve(newNumArgs);
773 newLocs.reserve(newNumArgs);
774 newInternalPaths.reserve(newNumArgs);
779 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
780 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
781 newDirections.push_back(existingDirections[oldIdx]);
782 newNames.push_back(existingNames[oldIdx]);
783 newTypes.push_back(existingTypes[oldIdx]);
784 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
785 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
786 newLocs.push_back(existingLocs[oldIdx]);
787 if (supportsInternalPaths)
788 newInternalPaths.push_back(internalPaths[oldIdx]);
792 for (
auto pair : llvm::enumerate(ports)) {
793 auto idx = pair.value().first;
794 auto &port = pair.value().second;
795 migrateOldPorts(idx);
797 newNames.push_back(port.name);
799 auto annos = port.annotations.getArrayAttr();
800 newAnnos.push_back(annos ? annos : emptyArray);
801 newSyms.push_back(port.sym);
802 newLocs.push_back(port.loc);
803 if (supportsInternalPaths)
804 newInternalPaths.push_back(emptyInternalPath);
806 migrateOldPorts(oldNumArgs);
810 if (llvm::all_of(newAnnos, [](Attribute attr) {
811 return cast<ArrayAttr>(attr).empty();
816 op->setAttr(
"portDirections",
818 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newNames));
819 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newTypes));
820 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newAnnos));
821 op.setPortSymbols(newSyms);
822 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newLocs));
823 if (supportsInternalPaths) {
825 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
826 return !cast<InternalPathAttr>(attr).getPath();
829 op->removeAttr(
"internalPaths");
831 op->setAttr(
"internalPaths",
837 static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
838 if (portIndices.none())
842 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
843 ArrayRef<Attribute> portNames = op.getPortNames();
844 ArrayRef<Attribute> portTypes = op.getPortTypes();
845 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
846 ArrayRef<Attribute> portSyms = op.getPortSymbols();
847 ArrayRef<Attribute> portLocs = op.getPortLocations();
848 auto numPorts = op.getNumPorts();
850 assert(portDirections.size() == numPorts);
851 assert(portNames.size() == numPorts);
852 assert(portAnnos.size() == numPorts || portAnnos.empty());
853 assert(portTypes.size() == numPorts);
854 assert(portSyms.size() == numPorts || portSyms.empty());
855 assert(portLocs.size() == numPorts);
857 SmallVector<bool> newPortDirections =
858 removeElementsAtIndices<bool>(portDirections, portIndices);
859 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
866 op->setAttr(
"portDirections",
868 op->setAttr(
"portNames",
ArrayAttr::get(op.getContext(), newPortNames));
869 op->setAttr(
"portAnnotations",
ArrayAttr::get(op.getContext(), newPortAnnos));
870 op->setAttr(
"portTypes",
ArrayAttr::get(op.getContext(), newPortTypes));
871 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
872 op->setAttr(
"portSyms",
ArrayAttr::get(op.getContext(), newPortSyms));
873 op->setAttr(
"portLocations",
ArrayAttr::get(op.getContext(), newPortLocs));
876 template <
typename T>
879 auto internalPaths = op.getInternalPaths();
887 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
888 return !cast<InternalPathAttr>(attr).getPath();
891 op.removeInternalPathsAttr();
893 op.setInternalPathsAttr(
ArrayAttr::get(op.getContext(), newPaths));
897 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
902 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
907 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
911 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
923 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
926 auto &[index, port] = ports[i];
927 body->insertArgument(index + i, port.type, port.loc);
949 StringAttr name, ArrayRef<PortInfo> ports,
950 ArrayAttr annotations, ArrayAttr layers,
951 bool withAnnotations,
bool withLayers) {
953 result.addAttribute(::mlir::SymbolTable::getSymbolAttrName(), name);
956 SmallVector<Direction, 4> portDirections;
957 SmallVector<Attribute, 4> portNames;
958 SmallVector<Attribute, 4> portTypes;
959 SmallVector<Attribute, 4> portAnnotations;
960 SmallVector<Attribute, 4> portSyms;
961 SmallVector<Attribute, 4> portLocs;
962 for (
const auto &port : ports) {
963 portDirections.push_back(port.direction);
964 portNames.push_back(port.name);
966 portAnnotations.push_back(port.annotations.getArrayAttr());
967 portSyms.push_back(port.sym);
968 portLocs.push_back(port.loc);
973 if (llvm::all_of(portAnnotations, [](Attribute attr) {
974 return cast<ArrayAttr>(attr).empty();
976 portAnnotations.clear();
978 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
983 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
984 result.addAttribute(
"portTypes", builder.getArrayAttr(portTypes));
985 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
986 result.addAttribute(
"portLocations", builder.getArrayAttr(portLocs));
988 if (withAnnotations) {
990 annotations = builder.getArrayAttr({});
991 result.addAttribute(
"annotations", annotations);
992 result.addAttribute(
"portAnnotations",
993 builder.getArrayAttr(portAnnotations));
998 layers = builder.getArrayAttr({});
999 result.addAttribute(
"layers", layers);
1006 StringAttr name, ArrayRef<PortInfo> ports,
1007 ArrayAttr annotations, ArrayAttr layers) {
1012 static void buildClass(OpBuilder &builder, OperationState &result,
1013 StringAttr name, ArrayRef<PortInfo> ports) {
1019 void FModuleOp::build(OpBuilder &builder, OperationState &result,
1020 StringAttr name, ConventionAttr convention,
1021 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1023 buildModule(builder, result, name, ports, annotations, layers);
1024 result.addAttribute(
"convention", convention);
1027 auto *bodyRegion = result.regions[0].get();
1029 bodyRegion->push_back(body);
1032 for (
auto &elt : ports)
1033 body->addArgument(elt.type, elt.loc);
1036 void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1037 StringAttr name, ConventionAttr convention,
1038 ArrayRef<PortInfo> ports, StringRef defnameAttr,
1039 ArrayAttr annotations, ArrayAttr parameters,
1040 ArrayAttr internalPaths, ArrayAttr layers) {
1041 buildModule(builder, result, name, ports, annotations, layers);
1042 result.addAttribute(
"convention", convention);
1043 if (!defnameAttr.empty())
1044 result.addAttribute(
"defname", builder.getStringAttr(defnameAttr));
1046 parameters = builder.getArrayAttr({});
1047 result.addAttribute(getParametersAttrName(result.name), parameters);
1048 if (internalPaths && !internalPaths.empty())
1049 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1052 void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1053 StringAttr name, ArrayRef<PortInfo> ports,
1054 StringRef intrinsicNameStr, ArrayAttr annotations,
1055 ArrayAttr parameters, ArrayAttr internalPaths,
1057 buildModule(builder, result, name, ports, annotations, layers);
1058 result.addAttribute(
"intrinsic", builder.getStringAttr(intrinsicNameStr));
1060 parameters = builder.getArrayAttr({});
1061 result.addAttribute(getParametersAttrName(result.name), parameters);
1062 if (internalPaths && !internalPaths.empty())
1063 result.addAttribute(getInternalPathsAttrName(result.name), internalPaths);
1066 void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1067 StringAttr name, ArrayRef<PortInfo> ports,
1068 uint32_t numReadPorts, uint32_t numWritePorts,
1069 uint32_t numReadWritePorts, uint32_t dataWidth,
1070 uint32_t maskBits, uint32_t readLatency,
1071 uint32_t writeLatency, uint64_t depth,
1072 ArrayAttr annotations, ArrayAttr layers) {
1073 auto *context = builder.getContext();
1074 buildModule(builder, result, name, ports, annotations, layers);
1077 result.addAttribute(
"numReadPorts",
IntegerAttr::get(ui32Type, numReadPorts));
1078 result.addAttribute(
"numWritePorts",
1080 result.addAttribute(
"numReadWritePorts",
1084 result.addAttribute(
"readLatency",
IntegerAttr::get(ui32Type, readLatency));
1085 result.addAttribute(
"writeLatency",
IntegerAttr::get(ui32Type, writeLatency));
1104 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1105 ArrayRef<Attribute> portAnnotations,
1106 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs) {
1109 bool printedNamesDontMatch =
false;
1111 mlir::OpPrintingFlags flags;
1115 SmallString<32> resultNameStr;
1117 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1128 resultNameStr.clear();
1129 llvm::raw_svector_ostream tmpStream(resultNameStr);
1130 p.printOperand(block->getArgument(i), tmpStream);
1133 auto portName = cast<StringAttr>(portNames[i]).getValue();
1134 if (!portName.empty() && tmpStream.str().drop_front() != portName)
1135 printedNamesDontMatch =
true;
1136 p << tmpStream.str();
1138 p.printKeywordOrString(cast<StringAttr>(portNames[i]).getValue());
1143 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1144 p.printType(portType);
1147 if (!portSyms.empty()) {
1148 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1150 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1156 if (!portAnnotations.empty() &&
1157 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1159 p.printAttribute(portAnnotations[i]);
1166 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1167 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1171 return printedNamesDontMatch;
1178 bool supportsSymbols,
1179 SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1180 SmallVectorImpl<Direction> &portDirections,
1181 SmallVectorImpl<Attribute> &portNames,
1182 SmallVectorImpl<Attribute> &portTypes,
1183 SmallVectorImpl<Attribute> &portAnnotations,
1184 SmallVectorImpl<Attribute> &portSyms,
1185 SmallVectorImpl<Attribute> &portLocs) {
1186 auto *context = parser.getContext();
1188 auto parseArgument = [&]() -> ParseResult {
1190 if (succeeded(parser.parseOptionalKeyword(
"out")))
1191 portDirections.push_back(Direction::Out);
1192 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
1193 portDirections.push_back(Direction::In);
1201 if (hasSSAIdentifiers) {
1202 OpAsmParser::Argument arg;
1203 if (parser.parseArgument(arg))
1205 entryArgs.push_back(arg);
1209 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1210 "Unknown MLIR name");
1211 if (
isdigit(arg.ssaName.name[1]))
1214 portNames.push_back(
1218 irLoc = arg.ssaName.location;
1222 irLoc = parser.getCurrentLocation();
1223 std::string portName;
1224 if (parser.parseKeywordOrString(&portName))
1231 if (parser.parseColonType(portType))
1235 if (hasSSAIdentifiers)
1236 entryArgs.back().type = portType;
1239 if (supportsSymbols) {
1240 hw::InnerSymAttr innerSymAttr;
1241 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1242 NamedAttrList dummyAttrs;
1243 if (parser.parseCustomAttributeWithFallback(
1244 innerSymAttr, ::mlir::Type{},
1246 return ::mlir::failure();
1249 portSyms.push_back(innerSymAttr);
1254 auto parseResult = parser.parseOptionalAttribute(annos);
1255 if (!parseResult.has_value())
1256 annos = parser.getBuilder().getArrayAttr({});
1257 else if (failed(*parseResult))
1259 portAnnotations.push_back(annos);
1262 std::optional<Location> maybeLoc;
1263 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1265 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1266 portLocs.push_back(loc);
1267 if (hasSSAIdentifiers)
1268 entryArgs.back().sourceLoc = loc;
1274 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1280 ArrayAttr parameters) {
1281 if (!parameters || parameters.empty())
1285 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1286 auto paramAttr = cast<ParamDeclAttr>(param);
1287 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1288 if (
auto value = paramAttr.getValue()) {
1290 p.printAttributeWithoutType(value);
1296 static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op) {
1299 // Print the visibility of the module.
1300 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1301 if (auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1302 p << visibility.getValue() << ' ';
1304 // Print the operation and the function name.
1305 p.printSymbolName(op.getModuleName());
1307 // Print the parameter list (if non-empty).
1308 printParameterList(p, op, op->getAttrOfType<ArrayAttr>("parameters"));
1310 // Both modules and external modules have a body, but it is always empty for
1311 // external modules.
1312 Block *body = nullptr;
1313 if (!op->getRegion(0).empty())
1314 body = &op->getRegion(0).front();
1316 auto needPortNamesAttr = printModulePorts(
1317 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1318 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations());
1320 SmallVector<StringRef, 12> omittedAttrs = {
1321 "sym_name", "portDirections", "portTypes", "portAnnotations",
1322 "portSyms", "portLocations", "parameters", visibilityAttrName};
1324 if (op.getConvention() == Convention::Internal)
1325 omittedAttrs.push_back("convention");
1327 // We can omit the portNames if they were able to be printed as properly as
1329 if (!needPortNamesAttr)
1330 omittedAttrs.push_back("portNames");
1332 // If there are no annotations we can omit the empty array.
1333 if (op->getAttrOfType<ArrayAttr>("annotations").empty())
1334 omittedAttrs.push_back("annotations");
1336 // If there are no enabled layers, then omit the empty array.
1337 if (auto layers = op->getAttrOfType<ArrayAttr>("layers"))
1339 omittedAttrs.push_back("layers");
1341 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1344 void FExtModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1346 void FIntModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1348 void FMemModuleOp::print(OpAsmPrinter &p) { printFModuleLikeOp(p, *this); }
1350 void FModuleOp::print(OpAsmPrinter &p) {
1351 printFModuleLikeOp(p, *this);
1353 // Print the body if this is not an external function. Since this block does
1354 // not have terminators, printing the terminator actually just prints the last
1356 Region &fbody = getBody();
1357 if (!fbody.empty()) {
1359 p.printRegion(fbody, /*printEntryBlockArgs=*/false,
1360 /*printBlockTerminators=*/true);
1370 parseOptionalParameters(OpAsmParser &parser,
1371 SmallVectorImpl<Attribute> ¶meters) {
1373 return parser.parseCommaSeparatedList(
1374 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1379 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1382 // Parse the default value if present.
1383 if (succeeded(parser.parseOptionalEqual())) {
1384 if (parser.parseAttribute(value, type))
1388 auto &builder = parser.getBuilder();
1389 parameters.push_back(ParamDeclAttr::get(
1390 builder.getContext(), builder.getStringAttr(name), type, value));
1396 static ParseResult parseParameterList(OpAsmParser &parser,
1397 ArrayAttr ¶meters) {
1398 SmallVector<Attribute> parseParameters;
1399 if (failed(parseOptionalParameters(parser, parseParameters)))
1402 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1407 static ParseResult parseFModuleLikeOp(OpAsmParser &parser,
1408 OperationState &result,
1409 bool hasSSAIdentifiers) {
1410 auto *context = result.getContext();
1411 auto &builder = parser.getBuilder();
1413 // Parse the visibility attribute.
1414 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1416 // Parse the name as a symbol.
1417 StringAttr nameAttr;
1418 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1422 // Parse optional parameters.
1423 SmallVector<Attribute, 4> parameters;
1424 if (parseOptionalParameters(parser, parameters))
1426 result.addAttribute("parameters", builder.getArrayAttr(parameters));
1428 // Parse the module ports.
1429 SmallVector<OpAsmParser::Argument> entryArgs;
1430 SmallVector<Direction, 4> portDirections;
1431 SmallVector<Attribute, 4> portNames;
1432 SmallVector<Attribute, 4> portTypes;
1433 SmallVector<Attribute, 4> portAnnotations;
1434 SmallVector<Attribute, 4> portSyms;
1435 SmallVector<Attribute, 4> portLocs;
1436 if (parseModulePorts(parser, hasSSAIdentifiers, /*supportsSymbols=*/true,
1437 entryArgs, portDirections, portNames, portTypes,
1438 portAnnotations, portSyms, portLocs))
1441 // If module attributes are present, parse them.
1442 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1445 assert(portNames.size() == portTypes.size());
1447 // Record the argument and result types as an attribute. This is necessary
1448 // for external modules.
1450 // Add port directions.
1451 if (!result.attributes.get("portDirections"))
1452 result.addAttribute("portDirections",
1453 direction::packAttribute(context, portDirections));
1456 if (!result.attributes.get("portNames"))
1457 result.addAttribute("portNames", builder.getArrayAttr(portNames));
1459 // Add the port types.
1460 if (!result.attributes.get("portTypes"))
1461 result.addAttribute("portTypes", ArrayAttr::get(context, portTypes));
1463 // Add the port annotations.
1464 if (!result.attributes.get("portAnnotations")) {
1465 // If there are no portAnnotations, don't add the attribute.
1466 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1467 return !cast<ArrayAttr>(anno).empty();
1469 result.addAttribute(
"portAnnotations",
1474 if (!result.attributes.get(
"portSyms")) {
1475 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1476 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
1480 if (!result.attributes.get(
"portLocations"))
1481 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1484 if (!result.attributes.get(
"annotations"))
1485 result.addAttribute(
"annotations", builder.getArrayAttr({}));
1489 if (!result.attributes.get(
"portAnnotations"))
1490 result.addAttribute(
"portAnnotations", builder.getArrayAttr({}));
1493 auto *body = result.addRegion();
1495 if (hasSSAIdentifiers) {
1496 if (parser.parseRegion(*body, entryArgs))
1499 body->push_back(
new Block());
1504 ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1507 if (!result.attributes.get(
"convention"))
1508 result.addAttribute(
1511 if (!result.attributes.get(
"layers"))
1512 result.addAttribute(
"layers",
ArrayAttr::get(parser.getContext(), {}));
1516 ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1519 if (!result.attributes.get(
"convention"))
1520 result.addAttribute(
1526 ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1530 ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1537 auto portTypes = getPortTypes();
1538 auto portLocs = getPortLocations();
1539 auto numPorts = portTypes.size();
1542 if (body->getNumArguments() != numPorts)
1543 return emitOpError(
"entry block must have ")
1544 << numPorts <<
" arguments to match module signature";
1547 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1548 if (arg.getType() != cast<TypeAttr>(type).getValue())
1549 return emitOpError(
"block argument types should match signature types");
1550 if (arg.getLoc() != cast<LocationAttr>(loc))
1552 "block argument locations should match signature locations");
1558 static LogicalResult
1560 std::optional<::mlir::ArrayAttr> internalPaths) {
1565 if (internalPaths->size() != op.getNumPorts())
1566 return op.emitError(
"module has inconsistent internal path array with ")
1567 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1571 for (
auto [idx, path, typeattr] : llvm::enumerate(
1572 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1573 if (path.getPath() &&
1574 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1576 op.emitError(
"module has internal path for non-ref-type port ")
1577 << op.getPortNameAttr(idx);
1578 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1589 auto params = getParameters();
1593 auto checkParmValue = [&](Attribute elt) ->
bool {
1594 auto param = cast<ParamDeclAttr>(elt);
1595 auto value = param.getValue();
1596 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1598 emitError() <<
"has unknown extmodule parameter value '"
1599 << param.getName().getValue() <<
"' = " << value;
1603 if (!llvm::all_of(params, checkParmValue))
1613 auto params = getParameters();
1617 auto checkParmValue = [&](Attribute elt) ->
bool {
1618 auto param = cast<ParamDeclAttr>(elt);
1619 auto value = param.getValue();
1620 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1622 emitError() <<
"has unknown intmodule parameter value '"
1623 << param.getName().getValue() <<
"' = " << value;
1627 if (!llvm::all_of(params, checkParmValue))
1634 CircuitOp circuitOp,
1635 SymbolTableCollection &symbolTable,
1637 auto layer = refType.getLayer();
1640 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1642 return emitError(loc) << start <<
" associated with layer '" << layer
1643 <<
"', but this layer was not defined";
1644 if (!isa<LayerOp>(layerOp)) {
1645 auto diag = emitError(loc)
1646 << start <<
" associated with layer '" << layer
1647 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1648 << LayerOp::getOperationName() <<
"' op";
1649 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1655 SymbolTableCollection &symbolTable) {
1657 auto circuitOp = module->getParentOfType<CircuitOp>();
1658 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1659 auto type = module.getPortType(i);
1661 if (
auto refType = type_dyn_cast<RefType>(type)) {
1663 refType, module.getPortLocation(i), circuitOp, symbolTable,
1664 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1669 if (
auto classType = dyn_cast<ClassType>(type)) {
1670 auto className = classType.getNameAttr();
1671 auto classOp = dyn_cast_or_null<ClassLike>(
1672 symbolTable.lookupSymbolIn(circuitOp, className));
1674 return module.emitOpError() <<
"references unknown class " << className;
1677 if (failed(classOp.verifyType(classType,
1678 [&]() { return module.emitOpError(); })))
1687 LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1692 auto circuitOp = (*this)->getParentOfType<CircuitOp>();
1693 for (
auto layer : getLayers()) {
1694 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1695 return emitOpError() <<
"enables unknown layer '" << layer <<
"'";
1702 FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1707 FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1712 FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1716 void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1721 void FExtModuleOp::getAsmBlockArgumentNames(
1726 void FIntModuleOp::getAsmBlockArgumentNames(
1731 void FMemModuleOp::getAsmBlockArgumentNames(
1736 ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1738 ArrayAttr FModuleOp::getParameters() {
return {}; }
1740 Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1742 ConventionAttr FIntModuleOp::getConventionAttr() {
1746 Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1748 ConventionAttr FMemModuleOp::getConventionAttr() {
1757 ClassLike classOp, ClassType type,
1758 function_ref<InFlightDiagnostic()> emitError) {
1760 auto name = type.getNameAttr().getAttr();
1761 auto expectedName = classOp.getModuleNameAttr();
1762 if (name != expectedName)
1763 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1766 auto elements = type.getElements();
1768 auto expectedNumElements = classOp.getNumPorts();
1770 return emitError() <<
"has wrong number of ports, got " <<
numElements
1771 <<
", expected " << expectedNumElements;
1773 auto portNames = classOp.getPortNames();
1774 auto portDirections = classOp.getPortDirections();
1775 auto portTypes = classOp.getPortTypes();
1778 auto element = elements[i];
1780 auto name = element.name;
1781 auto expectedName = portNames[i];
1782 if (name != expectedName)
1783 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
1784 <<
", expected " << expectedName;
1786 auto direction = element.direction;
1787 auto expectedDirection =
Direction(portDirections[i]);
1788 if (direction != expectedDirection)
1789 return emitError() <<
"port " << name <<
" has wrong direction, got "
1793 auto type = element.type;
1794 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
1795 if (type != expectedType)
1796 return emitError() <<
"port " << name <<
" has wrong type, got " << type
1797 <<
", expected " << expectedType;
1804 auto n = classOp.getNumPorts();
1805 SmallVector<ClassElement> elements;
1806 elements.reserve(n);
1807 for (
size_t i = 0; i < n; ++i)
1808 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
1809 classOp.getPortDirection(i)});
1815 bool hasSSAIdentifiers) {
1816 auto *context = result.getContext();
1817 auto &builder = parser.getBuilder();
1820 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1823 StringAttr nameAttr;
1824 if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
1829 SmallVector<OpAsmParser::Argument> entryArgs;
1830 SmallVector<Direction, 4> portDirections;
1831 SmallVector<Attribute, 4> portNames;
1832 SmallVector<Attribute, 4> portTypes;
1833 SmallVector<Attribute, 4> portAnnotations;
1834 SmallVector<Attribute, 4> portSyms;
1835 SmallVector<Attribute, 4> portLocs;
1837 false, entryArgs, portDirections,
1838 portNames, portTypes, portAnnotations, portSyms,
1843 for (
auto annos : portAnnotations)
1844 if (!cast<ArrayAttr>(annos).empty())
1848 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1851 assert(portNames.size() == portTypes.size());
1857 if (!result.attributes.get(
"portDirections"))
1858 result.addAttribute(
"portDirections",
1862 if (!result.attributes.get(
"portNames"))
1863 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
1866 if (!result.attributes.get(
"portTypes"))
1867 result.addAttribute(
"portTypes", builder.getArrayAttr(portTypes));
1870 if (!result.attributes.get(
"portSyms")) {
1871 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1872 result.addAttribute(
"portSyms", builder.getArrayAttr(portSyms));
1876 if (!result.attributes.get(
"portLocations"))
1877 result.addAttribute(
"portLocations",
ArrayAttr::get(context, portLocs));
1883 auto *bodyRegion = result.addRegion();
1885 if (hasSSAIdentifiers) {
1886 if (parser.parseRegion(*bodyRegion, entryArgs))
1888 if (bodyRegion->empty())
1889 bodyRegion->push_back(
new Block());
1899 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1900 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1901 p << visibility.getValue() <<
' ';
1904 p.printSymbolName(op.getName());
1908 Region ®ion = op->getRegion(0);
1909 Block *body =
nullptr;
1910 if (!region.empty())
1911 body = ®ion.front();
1914 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1915 {}, op.getPortSymbols(), op.getPortLocations());
1918 SmallVector<StringRef, 8> omittedAttrs = {
1919 "sym_name",
"portNames",
"portTypes",
"portDirections",
1920 "portSyms",
"portLocations", visibilityAttrName};
1924 if (!needPortNamesAttr)
1925 omittedAttrs.push_back(
"portNames");
1927 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1930 if (!region.empty()) {
1932 auto printEntryBlockArgs =
false;
1933 auto printBlockTerminators =
false;
1934 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
1942 void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
1943 ArrayRef<PortInfo> ports) {
1946 [](
const auto &port) {
return port.annotations.empty(); }) &&
1947 "class ports may not have annotations");
1952 auto *bodyRegion = result.regions[0].get();
1954 bodyRegion->push_back(body);
1957 for (
auto &elt : ports)
1958 body->addArgument(elt.type, elt.loc);
1961 void ClassOp::print(OpAsmPrinter &p) {
1965 ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
1966 auto hasSSAIdentifiers =
true;
1972 auto type = operand.getType();
1973 if (!isa<PropertyType>(type)) {
1974 emitOpError(
"ports on a class must be properties");
1983 ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
1987 void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1992 SmallVector<PortInfo> ClassOp::getPorts() {
1997 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2002 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2005 Convention ClassOp::getConvention() {
return Convention::Internal; }
2007 ConventionAttr ClassOp::getConventionAttr() {
2011 ArrayAttr ClassOp::getParameters() {
return {}; }
2013 ArrayAttr ClassOp::getPortAnnotationsAttr() {
2017 ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2019 ArrayRef<Attribute> ClassOp::getLayers() {
return getLayersAttr(); }
2029 BlockArgument ClassOp::getArgument(
size_t portNumber) {
2033 bool ClassOp::canDiscardOnUseEmpty() {
2044 void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2045 StringAttr name, ArrayRef<PortInfo> ports) {
2048 [](
const auto &port) {
return port.annotations.empty(); }) &&
2049 "class ports may not have annotations");
2054 void ExtClassOp::print(OpAsmPrinter &p) {
2058 ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2059 auto hasSSAIdentifiers =
false;
2064 ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2068 void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2073 SmallVector<PortInfo> ExtClassOp::getPorts() {
2078 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2082 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2085 Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2087 ConventionAttr ExtClassOp::getConventionAttr() {
2091 ArrayAttr ExtClassOp::getLayersAttr() {
2095 ArrayRef<Attribute> ExtClassOp::getLayers() {
return getLayersAttr(); }
2097 ArrayAttr ExtClassOp::getParameters() {
return {}; }
2099 ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2111 bool ExtClassOp::canDiscardOnUseEmpty() {
2122 void InstanceOp::build(
2123 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2124 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2125 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2126 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2127 ArrayRef<Attribute> layers,
bool lowerToBind, StringAttr innerSym) {
2128 build(builder, result, resultTypes, moduleName, name, nameKind,
2129 portDirections, portNames, annotations, portAnnotations, layers,
2134 void InstanceOp::build(
2135 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2136 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2137 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2138 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2139 ArrayRef<Attribute> layers,
bool lowerToBind, hw::InnerSymAttr innerSym) {
2140 result.addTypes(resultTypes);
2141 result.addAttribute(
"moduleName",
2143 result.addAttribute(
"name", builder.getStringAttr(name));
2144 result.addAttribute(
2147 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
2148 result.addAttribute(
"annotations", builder.getArrayAttr(annotations));
2149 result.addAttribute(
"layers", builder.getArrayAttr(layers));
2151 result.addAttribute(
"lowerToBind", builder.getUnitAttr());
2153 result.addAttribute(
"inner_sym", innerSym);
2154 result.addAttribute(
"nameKind",
2157 if (portAnnotations.empty()) {
2158 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2159 builder.getArrayAttr({}));
2160 result.addAttribute(
"portAnnotations",
2161 builder.getArrayAttr(portAnnotationsVec));
2163 assert(portAnnotations.size() == resultTypes.size());
2164 result.addAttribute(
"portAnnotations",
2165 builder.getArrayAttr(portAnnotations));
2169 void InstanceOp::build(OpBuilder &builder, OperationState &result,
2170 FModuleLike module, StringRef name,
2171 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2172 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2173 hw::InnerSymAttr innerSym) {
2176 SmallVector<Type> resultTypes;
2177 resultTypes.reserve(module.getNumPorts());
2179 module.getPortTypes(), std::back_inserter(resultTypes),
2180 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2183 ArrayAttr portAnnotationsAttr;
2184 if (portAnnotations.empty()) {
2185 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2186 resultTypes.size(), builder.getArrayAttr({})));
2188 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2192 builder, result, resultTypes,
2194 builder.getStringAttr(name),
2196 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2197 builder.getArrayAttr(annotations), portAnnotationsAttr,
2198 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2202 void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2203 ArrayRef<PortInfo> ports, StringRef moduleName,
2204 StringRef name, NameKindEnum nameKind,
2205 ArrayRef<Attribute> annotations,
2206 ArrayRef<Attribute> layers,
bool lowerToBind,
2207 hw::InnerSymAttr innerSym) {
2209 SmallVector<Type> newResultTypes;
2210 SmallVector<Direction> newPortDirections;
2211 SmallVector<Attribute> newPortNames;
2212 SmallVector<Attribute> newPortAnnotations;
2213 for (
auto &p : ports) {
2214 newResultTypes.push_back(p.type);
2215 newPortDirections.push_back(p.direction);
2216 newPortNames.push_back(p.name);
2217 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2220 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2221 newPortDirections, newPortNames, annotations, newPortAnnotations,
2222 layers, lowerToBind, innerSym);
2228 SmallVector<SymbolRefAttr> missingLayers;
2229 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2231 missingLayers.push_back(layer);
2233 if (missingLayers.empty())
2237 emitOpError(
"ambient layers are insufficient to instantiate module");
2238 auto ¬e = diag.attachNote();
2239 note <<
"missing layer requirements: ";
2240 interleaveComma(missingLayers, note);
2247 const llvm::BitVector &portIndices) {
2248 assert(portIndices.size() >= getNumResults() &&
2249 "portIndices is not at least as large as getNumResults()");
2251 if (portIndices.none())
2254 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2255 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2256 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2258 SmallVector<Attribute> newPortNames =
2260 SmallVector<Attribute> newPortAnnotations =
2263 auto newOp = builder.create<InstanceOp>(
2264 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2265 newPortDirections, newPortNames, getAnnotations().getValue(),
2266 newPortAnnotations, getLayers(), getLowerToBind(), getInnerSymAttr());
2268 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2269 oldIdx != numOldPorts; ++oldIdx) {
2270 if (portIndices.test(oldIdx)) {
2271 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2274 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2282 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2283 newOp->setAttr(
"output_file", outputFile);
2288 ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2289 assert(portIdx < getNumResults() &&
2290 "index should be smaller than result number");
2291 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2294 void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2295 assert(annotations.size() == getNumResults() &&
2296 "number of annotations is not equal to result number");
2297 (*this)->setAttr(
"portAnnotations",
2302 InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2303 auto portSize = ports.size();
2304 auto newPortCount = getNumResults() + portSize;
2305 SmallVector<Direction> newPortDirections;
2306 newPortDirections.reserve(newPortCount);
2307 SmallVector<Attribute> newPortNames;
2308 newPortNames.reserve(newPortCount);
2309 SmallVector<Type> newPortTypes;
2310 newPortTypes.reserve(newPortCount);
2311 SmallVector<Attribute> newPortAnnos;
2312 newPortAnnos.reserve(newPortCount);
2314 unsigned oldIndex = 0;
2315 unsigned newIndex = 0;
2316 while (oldIndex + newIndex < newPortCount) {
2318 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2319 auto &newPort = ports[newIndex].second;
2320 newPortDirections.push_back(newPort.direction);
2321 newPortNames.push_back(newPort.name);
2322 newPortTypes.push_back(newPort.type);
2323 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2327 newPortDirections.push_back(getPortDirection(oldIndex));
2328 newPortNames.push_back(getPortName(oldIndex));
2329 newPortTypes.push_back(getType(oldIndex));
2330 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2336 return OpBuilder(*this).create<InstanceOp>(
2337 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2338 newPortDirections, newPortNames, getAnnotations().getValue(),
2339 newPortAnnos, getLayers(), getLowerToBind(), getInnerSymAttr());
2342 LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2344 getModuleNameAttr());
2349 StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2351 void InstanceOp::print(OpAsmPrinter &p) {
2354 p.printKeywordOrString(
getName());
2355 if (
auto attr = getInnerSymAttr()) {
2357 p.printSymbolName(attr.getSymName());
2359 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2360 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2363 SmallVector<StringRef, 10> omittedAttrs = {
2364 "moduleName",
"name",
"portDirections",
2365 "portNames",
"portTypes",
"portAnnotations",
2366 "inner_sym",
"nameKind"};
2367 if (getAnnotations().
empty())
2368 omittedAttrs.push_back(
"annotations");
2369 if (getLayers().
empty())
2370 omittedAttrs.push_back(
"layers");
2371 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2375 p.printSymbolName(getModuleName());
2378 SmallVector<Attribute> portTypes;
2379 portTypes.reserve(getNumResults());
2380 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2383 getPortNames().getValue(), portTypes,
2384 getPortAnnotations().getValue(), {}, {});
2387 ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2388 auto *context = parser.getContext();
2389 auto &resultAttrs = result.attributes;
2392 hw::InnerSymAttr innerSymAttr;
2393 FlatSymbolRefAttr moduleName;
2394 SmallVector<OpAsmParser::Argument> entryArgs;
2395 SmallVector<Direction, 4> portDirections;
2396 SmallVector<Attribute, 4> portNames;
2397 SmallVector<Attribute, 4> portTypes;
2398 SmallVector<Attribute, 4> portAnnotations;
2399 SmallVector<Attribute, 4> portSyms;
2400 SmallVector<Attribute, 4> portLocs;
2401 NameKindEnumAttr nameKind;
2403 if (parser.parseKeywordOrString(&name))
2405 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2406 if (parser.parseCustomAttributeWithFallback(
2407 innerSymAttr, ::mlir::Type{},
2408 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2409 result.attributes)) {
2410 return ::mlir::failure();
2414 parser.parseOptionalAttrDict(result.attributes) ||
2415 parser.parseAttribute(moduleName,
"moduleName", resultAttrs) ||
2417 false, entryArgs, portDirections,
2418 portNames, portTypes, portAnnotations, portSyms,
2424 if (!resultAttrs.get(
"moduleName"))
2425 result.addAttribute(
"moduleName", moduleName);
2426 if (!resultAttrs.get(
"name"))
2428 result.addAttribute(
"nameKind", nameKind);
2429 if (!resultAttrs.get(
"portDirections"))
2430 result.addAttribute(
"portDirections",
2432 if (!resultAttrs.get(
"portNames"))
2433 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2434 if (!resultAttrs.get(
"portAnnotations"))
2435 result.addAttribute(
"portAnnotations",
2440 if (!resultAttrs.get(
"annotations"))
2441 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2442 if (!resultAttrs.get(
"layers"))
2443 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2446 result.types.reserve(portTypes.size());
2448 portTypes, std::back_inserter(result.types),
2449 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2459 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2460 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2464 std::optional<size_t> InstanceOp::getTargetResultIndex() {
2466 return std::nullopt;
2473 void InstanceChoiceOp::build(
2474 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2475 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2476 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2477 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2479 SmallVector<Type> resultTypes;
2480 for (Attribute portType : defaultModule.getPortTypes())
2481 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2484 ArrayAttr portAnnotationsAttr;
2485 if (portAnnotations.empty()) {
2486 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2487 resultTypes.size(), builder.getArrayAttr({})));
2489 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2493 SmallVector<Attribute> moduleNames, caseNames;
2495 for (
auto [caseOption, caseModule] : cases) {
2496 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2498 {SymbolRefAttr::get(caseOption)}));
2502 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2503 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2505 defaultModule.getPortDirectionsAttr(),
2506 defaultModule.getPortNamesAttr(),
2507 builder.getArrayAttr(annotations), portAnnotationsAttr,
2508 defaultModule.getLayersAttr(),
2512 std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2513 return std::nullopt;
2516 void InstanceChoiceOp::print(OpAsmPrinter &p) {
2519 p.printKeywordOrString(
getName());
2520 if (
auto attr = getInnerSymAttr()) {
2522 p.printSymbolName(attr.getSymName());
2524 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2525 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2528 SmallVector<StringRef, 10> omittedAttrs = {
2529 "moduleNames",
"caseNames",
"name",
2530 "portDirections",
"portNames",
"portTypes",
2531 "portAnnotations",
"inner_sym",
"nameKind"};
2532 if (getAnnotations().
empty())
2533 omittedAttrs.push_back(
"annotations");
2534 if (getLayers().
empty())
2535 omittedAttrs.push_back(
"layers");
2536 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2541 auto moduleNames = getModuleNamesAttr();
2542 auto caseNames = getCaseNamesAttr();
2544 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2546 p <<
" alternatives ";
2548 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2550 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2554 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2555 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2557 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2563 SmallVector<Attribute> portTypes;
2564 portTypes.reserve(getNumResults());
2565 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2568 getPortNames().getValue(), portTypes,
2569 getPortAnnotations().getValue(), {}, {});
2572 ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2573 OperationState &result) {
2574 auto *context = parser.getContext();
2575 auto &resultAttrs = result.attributes;
2578 hw::InnerSymAttr innerSymAttr;
2579 SmallVector<Attribute> moduleNames;
2580 SmallVector<Attribute> caseNames;
2581 SmallVector<OpAsmParser::Argument> entryArgs;
2582 SmallVector<Direction, 4> portDirections;
2583 SmallVector<Attribute, 4> portNames;
2584 SmallVector<Attribute, 4> portTypes;
2585 SmallVector<Attribute, 4> portAnnotations;
2586 SmallVector<Attribute, 4> portSyms;
2587 SmallVector<Attribute, 4> portLocs;
2588 NameKindEnumAttr nameKind;
2590 if (parser.parseKeywordOrString(&name))
2592 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2593 if (parser.parseCustomAttributeWithFallback(
2594 innerSymAttr, Type{},
2595 hw::InnerSymbolTable::getInnerSymbolAttrName(),
2596 result.attributes)) {
2601 parser.parseOptionalAttrDict(result.attributes))
2604 FlatSymbolRefAttr defaultModuleName;
2605 if (parser.parseAttribute(defaultModuleName))
2607 moduleNames.push_back(defaultModuleName);
2611 FlatSymbolRefAttr optionName;
2612 if (parser.parseKeyword(
"alternatives") ||
2613 parser.parseAttribute(optionName) || parser.parseLBrace())
2616 FlatSymbolRefAttr moduleName;
2617 StringAttr caseName;
2618 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2619 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2621 moduleNames.push_back(moduleName);
2623 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2624 if (failed(parser.parseOptionalComma()))
2627 if (parser.parseRBrace())
2632 false, entryArgs, portDirections,
2633 portNames, portTypes, portAnnotations, portSyms,
2639 if (!resultAttrs.get(
"moduleNames"))
2640 result.addAttribute(
"moduleNames",
ArrayAttr::get(context, moduleNames));
2641 if (!resultAttrs.get(
"caseNames"))
2642 result.addAttribute(
"caseNames",
ArrayAttr::get(context, caseNames));
2643 if (!resultAttrs.get(
"name"))
2645 result.addAttribute(
"nameKind", nameKind);
2646 if (!resultAttrs.get(
"portDirections"))
2647 result.addAttribute(
"portDirections",
2649 if (!resultAttrs.get(
"portNames"))
2650 result.addAttribute(
"portNames",
ArrayAttr::get(context, portNames));
2651 if (!resultAttrs.get(
"portAnnotations"))
2652 result.addAttribute(
"portAnnotations",
2657 if (!resultAttrs.get(
"annotations"))
2658 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
2659 if (!resultAttrs.get(
"layers"))
2660 resultAttrs.append(
"layers", parser.getBuilder().getArrayAttr({}));
2663 result.types.reserve(portTypes.size());
2665 portTypes, std::back_inserter(result.types),
2666 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2673 for (
auto [result, name] : llvm::zip(getResults(), getPortNames()))
2674 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
2678 if (getCaseNamesAttr().
empty())
2679 return emitOpError() <<
"must have at least one case";
2680 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2681 return emitOpError() <<
"number of referenced modules does not match the "
2682 "number of options";
2687 SmallVector<SymbolRefAttr> missingLayers;
2688 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2690 missingLayers.push_back(layer);
2692 if (missingLayers.empty())
2696 emitOpError(
"ambient layers are insufficient to instantiate module");
2697 auto ¬e = diag.attachNote();
2698 note <<
"missing layer requirements: ";
2699 interleaveComma(missingLayers, note);
2704 InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2705 auto caseNames = getCaseNamesAttr();
2706 for (
auto moduleName : getModuleNamesAttr()) {
2708 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
2712 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
2713 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2714 auto ref = cast<SymbolRefAttr>(caseNames[i]);
2715 auto refRoot = ref.getRootReference();
2716 if (ref.getRootReference() != root)
2717 return emitOpError() <<
"case " << ref
2718 <<
" is not in the same option group as "
2721 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2722 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2724 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2725 return emitOpError() <<
"option " << refRoot
2726 <<
" does not contain option case " << ref;
2733 InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2734 auto caseNames = getCaseNamesAttr();
2735 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2736 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
2737 if (caseSym == option.getSymName())
2738 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
2740 return getDefaultTargetAttr();
2743 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2744 InstanceChoiceOp::getTargetChoices() {
2745 auto caseNames = getCaseNamesAttr();
2746 auto moduleNames = getModuleNamesAttr();
2747 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2748 for (
size_t i = 0; i < caseNames.size(); ++i) {
2749 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
2750 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
2758 const llvm::BitVector &portIndices) {
2759 assert(portIndices.size() >= getNumResults() &&
2760 "portIndices is not at least as large as getNumResults()");
2762 if (portIndices.none())
2765 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2766 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2767 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2769 SmallVector<Attribute> newPortNames =
2771 SmallVector<Attribute> newPortAnnotations =
2774 auto newOp = builder.create<InstanceChoiceOp>(
2775 getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
getName(),
2777 ArrayAttr::get(getContext(), newPortNames), getAnnotationsAttr(),
2781 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2782 oldIdx != numOldPorts; ++oldIdx) {
2783 if (portIndices.test(oldIdx)) {
2784 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2787 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2795 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2796 newOp->setAttr(
"output_file", outputFile);
2805 void MemOp::build(OpBuilder &builder, OperationState &result,
2806 TypeRange resultTypes, uint32_t readLatency,
2807 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2808 ArrayRef<Attribute> portNames, StringRef name,
2809 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2810 ArrayRef<Attribute> portAnnotations,
2811 hw::InnerSymAttr innerSym) {
2812 result.addAttribute(
2814 builder.getIntegerAttr(builder.getIntegerType(32), readLatency));
2815 result.addAttribute(
2817 builder.getIntegerAttr(builder.getIntegerType(32), writeLatency));
2818 result.addAttribute(
2819 "depth", builder.getIntegerAttr(builder.getIntegerType(64), depth));
2821 result.addAttribute(
"portNames", builder.getArrayAttr(portNames));
2822 result.addAttribute(
"name", builder.getStringAttr(name));
2823 result.addAttribute(
"nameKind",
2825 result.addAttribute(
"annotations", builder.getArrayAttr(annotations));
2827 result.addAttribute(
"inner_sym", innerSym);
2828 result.addTypes(resultTypes);
2830 if (portAnnotations.empty()) {
2831 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2832 builder.getArrayAttr({}));
2833 result.addAttribute(
"portAnnotations",
2834 builder.getArrayAttr(portAnnotationsVec));
2836 assert(portAnnotations.size() == resultTypes.size());
2837 result.addAttribute(
"portAnnotations",
2838 builder.getArrayAttr(portAnnotations));
2842 void MemOp::build(OpBuilder &builder, OperationState &result,
2843 TypeRange resultTypes, uint32_t readLatency,
2844 uint32_t writeLatency, uint64_t depth, RUWAttr ruw,
2845 ArrayRef<Attribute> portNames, StringRef name,
2846 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2847 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2848 build(builder, result, resultTypes, readLatency, writeLatency, depth, ruw,
2849 portNames, name, nameKind, annotations, portAnnotations,
2853 ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2854 assert(portIdx < getNumResults() &&
2855 "index should be smaller than result number");
2856 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2859 void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2860 assert(annotations.size() == getNumResults() &&
2861 "number of annotations is not equal to result number");
2862 (*this)->setAttr(
"portAnnotations",
2868 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2871 numReadWritePorts = 0;
2873 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2874 auto portKind = getPortKind(i);
2875 if (portKind == MemOp::PortKind::Debug)
2877 else if (portKind == MemOp::PortKind::Read)
2879 else if (portKind == MemOp::PortKind::Write) {
2882 ++numReadWritePorts;
2891 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2897 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2898 auto portName = getPortName(i);
2903 BundleType portBundleType =
2904 type_dyn_cast<BundleType>(getResult(i).getType());
2907 if (!portNamesSet.insert(portName).second) {
2908 emitOpError() <<
"has non-unique port name " << portName;
2916 auto elt = getPortNamed(portName);
2918 emitOpError() <<
"could not get port with name " << portName;
2921 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2924 if (portKind == MemOp::PortKind::Debug &&
2925 !type_isa<RefType>(getResult(i).getType()))
2926 return emitOpError() <<
"has an invalid type on port " << portName
2927 <<
" (expected Read/Write/ReadWrite/Debug)";
2928 if (type_isa<RefType>(firrtlType) && e == 1)
2929 return emitOpError()
2930 <<
"cannot have only one port of debug type. Debug port can only "
2931 "exist alongside other read/write/read-write port";
2936 if (portKind == MemOp::PortKind::Debug) {
2937 auto resType = type_cast<RefType>(getResult(i).getType());
2938 if (!(resType && type_isa<FVectorType>(resType.getType())))
2939 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2940 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2942 auto dataTypeOption = portBundleType.getElement(
"data");
2943 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2944 dataTypeOption = portBundleType.getElement(
"wdata");
2945 if (!dataTypeOption) {
2946 emitOpError() <<
"has no data field on port " << portName
2947 <<
" (expected to see \"data\" for a read or write "
2948 "port or \"rdata\" for a read/write port)";
2951 dataType = dataTypeOption->type;
2953 if (portKind == MemOp::PortKind::Read) {
2960 emitOpError() <<
"has non-passive data type on port " << portName
2961 <<
" (memory types must be passive)";
2966 if (dataType.containsAnalog()) {
2967 emitOpError() <<
"has a data type that contains an analog type on port "
2969 <<
" (memory types cannot contain analog types)";
2977 getTypeForPort(getDepth(), dataType, portKind,
2978 dataType.isGround() ? getMaskBits() : 0);
2981 auto originalType = getResult(i).getType();
2982 if (originalType != expectedType) {
2983 StringRef portKindName;
2985 case MemOp::PortKind::Read:
2986 portKindName =
"read";
2988 case MemOp::PortKind::Write:
2989 portKindName =
"write";
2991 case MemOp::PortKind::ReadWrite:
2992 portKindName =
"readwrite";
2994 case MemOp::PortKind::Debug:
2995 portKindName =
"dbg";
2998 emitOpError() <<
"has an invalid type for port " << portName
2999 <<
" of determined kind \"" << portKindName
3000 <<
"\" (expected " << expectedType <<
", but got "
3001 << originalType <<
")";
3007 if (oldDataType && oldDataType != dataType) {
3008 emitOpError() <<
"port " << getPortName(i)
3009 <<
" has a different type than port " << getPortName(i - 1)
3010 <<
" (expected " << oldDataType <<
", but got " << dataType
3015 oldDataType = dataType;
3018 auto maskWidth = getMaskBits();
3020 auto dataWidth = getDataType().getBitWidthOrSentinel();
3021 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3022 return emitOpError(
"the mask width cannot be greater than "
3025 if (getPortAnnotations().size() != getNumResults())
3026 return emitOpError(
"the number of result annotations should be "
3027 "equal to the number of results");
3033 return std::max(1U, llvm::Log2_64_Ceil(depth));
3039 PortKind portKind,
size_t maskBits) {
3041 auto *context = dataType.getContext();
3042 if (portKind == PortKind::Debug)
3051 auto getId = [&](StringRef name) -> StringAttr {
3055 SmallVector<BundleType::BundleElement, 7> portFields;
3059 portFields.push_back({getId(
"addr"),
false, addressType});
3060 portFields.push_back({getId(
"en"),
false,
UIntType::get(context, 1)});
3061 portFields.push_back({getId(
"clk"),
false,
ClockType::get(context)});
3064 case PortKind::Read:
3065 portFields.push_back({getId(
"data"),
true, dataType});
3068 case PortKind::Write:
3069 portFields.push_back({getId(
"data"),
false, dataType});
3070 portFields.push_back({getId(
"mask"),
false, maskType});
3073 case PortKind::ReadWrite:
3074 portFields.push_back({getId(
"rdata"),
true, dataType});
3075 portFields.push_back({getId(
"wmode"),
false,
UIntType::get(context, 1)});
3076 portFields.push_back({getId(
"wdata"),
false, dataType});
3077 portFields.push_back({getId(
"wmask"),
false, maskType});
3080 llvm::report_fatal_error(
"memory port kind not handled");
3088 SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3089 SmallVector<MemOp::NamedPort> result;
3091 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3093 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3100 MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3102 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3106 MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3108 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3112 size_t MemOp::getMaskBits() {
3114 for (
auto res : getResults()) {
3115 if (type_isa<RefType>(res.getType()))
3117 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3123 for (
auto t : type_cast<BundleType>(firstPortType.getPassiveType())) {
3124 if (t.name.getValue().contains(
"mask"))
3127 if (type_isa<UIntType>(mType))
3137 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3139 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3140 return type_cast<FVectorType>(refType.getType()).getElementType();
3141 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3143 StringRef dataFieldName =
"data";
3145 dataFieldName =
"rdata";
3147 return type_cast<BundleType>(firstPortType.getPassiveType())
3148 .getElementType(dataFieldName);
3151 StringAttr MemOp::getPortName(
size_t resultNo) {
3152 return cast<StringAttr>(getPortNames()[resultNo]);
3156 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3159 Value MemOp::getPortNamed(StringAttr name) {
3160 auto namesArray = getPortNames();
3161 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3162 if (namesArray[i] == name) {
3163 assert(i < getNumResults() &&
" names array out of sync with results");
3164 return getResult(i);
3173 size_t numReadPorts = 0;
3174 size_t numWritePorts = 0;
3175 size_t numReadWritePorts = 0;
3177 SmallVector<int32_t> writeClockIDs;
3179 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3180 auto portKind = op.getPortKind(i);
3181 if (portKind == MemOp::PortKind::Read)
3183 else if (portKind == MemOp::PortKind::Write) {
3184 for (
auto *a : op.getResult(i).getUsers()) {
3185 auto subfield = dyn_cast<SubfieldOp>(a);
3186 if (!subfield || subfield.getFieldIndex() != 2)
3188 auto clockPort = a->getResult(0);
3189 for (
auto *b : clockPort.getUsers()) {
3190 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3191 if (
connect.getDest() == clockPort) {
3194 connect.getSrc(),
true,
true,
true),
3196 if (result.second) {
3197 writeClockIDs.push_back(numWritePorts);
3199 writeClockIDs.push_back(result.first->second);
3208 ++numReadWritePorts;
3215 op.emitError(
"'firrtl.mem' should have simple type and known width");
3216 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3218 if (op->hasAttr(
"modName"))
3219 modName = op->getAttrOfType<StringAttr>(
"modName");
3221 SmallString<8> clocks;
3222 for (
auto a : writeClockIDs)
3223 clocks.append(Twine((
char)(a +
'a')).str());
3224 SmallString<32> initStr;
3229 for (
auto c : init.getFilename().getValue())
3230 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3231 (c >=
'0' && c <=
'9'))
3232 initStr.push_back(c);
3233 initStr.push_back(
'_');
3234 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3235 initStr.push_back(
'_');
3236 initStr.push_back(init.getIsInline() ?
't' :
'f');
3241 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3242 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3243 numReadWritePorts, (
size_t)
width, op.getDepth(),
3244 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3245 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3246 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3248 return {numReadPorts,
3253 op.getReadLatency(),
3254 op.getWriteLatency(),
3256 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3257 seq::WUW::PortOrder,
3260 op.getMaskBits() > 1,
3271 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3272 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3276 std::optional<size_t> MemOp::getTargetResultIndex() {
3278 return std::nullopt;
3282 StringAttr FirMemory::getFirMemoryName()
const {
return modName; }
3289 setNameFn(op.getDataRaw(), name);
3290 if (op.isForceable())
3291 setNameFn(op.getDataRef(), (name +
"_ref").str());
3299 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3300 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3301 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3302 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3303 if (operands.empty())
3305 inferredReturnTypes.push_back(operands[0].getType());
3306 for (
auto &attr : attributes)
3307 if (attr.getName() == Forceable::getForceableAttrName()) {
3308 auto forceableType =
3310 if (!forceableType) {
3312 ::mlir::emitError(*location,
"cannot force a node of type ")
3313 << operands[0].getType();
3316 inferredReturnTypes.push_back(forceableType);
3321 std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3327 std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3329 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3330 RegOp::computeDataFlow() {
3336 auto reset = getResetValue();
3343 return emitError(
"type mismatch between register ")
3344 << regType <<
" and reset value " << resetType;
3349 std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3359 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3360 RegResetOp::computeDataFlow() {
3365 std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3367 LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3368 auto refType = type_dyn_cast<RefType>(getType(0));
3373 refType, getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3374 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3377 void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3379 build(builder, state, klass.getInstanceType(),
3385 LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3386 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3387 auto classType = getType();
3388 auto className = classType.getNameAttr();
3391 auto classOp = dyn_cast_or_null<ClassLike>(
3392 symbolTable.lookupSymbolIn(circuitOp, className));
3394 return emitOpError() <<
"references unknown class " << className;
3397 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3403 StringAttr ObjectOp::getClassNameAttr() {
3404 return getType().getNameAttr().getAttr();
3407 StringRef ObjectOp::getClassName() {
return getType().getName(); }
3409 ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3410 auto symRef = getType().getNameAttr();
3411 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3414 Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3415 return getReferencedClass(symtbl);
3420 StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3422 StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3424 StringAttr ObjectOp::getReferencedModuleNameAttr() {
3425 return getClassNameAttr();
3429 setNameFn(getResult(),
getName());
3438 std::optional<int32_t> commonWidth;
3439 for (
auto operand : getOperands()) {
3440 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3444 commonWidth = thisWidth;
3447 if (commonWidth != thisWidth)
3448 return emitOpError(
"is inavlid as not all known operand widths match");
3455 Value dst =
connect->getOperand(0);
3456 Value src =
connect->getOperand(1);
3467 auto diag = emitError(
connect->getLoc());
3468 diag <<
"connect has invalid flow: the source expression ";
3470 diag <<
"\"" << srcName <<
"\" ";
3471 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3472 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3480 auto diag = emitError(
connect->getLoc());
3481 diag <<
"connect has invalid flow: the destination expression ";
3483 diag <<
"\"" << dstName <<
"\" ";
3484 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3485 return diag.attachNote(dstRef.getLoc())
3486 <<
"the destination was defined here";
3495 bool outerTypeIsConst =
false) {
3496 auto typeIsConst = outerTypeIsConst || type.
isConst();
3501 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3502 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3503 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3507 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3519 auto dest =
connect.getDest();
3520 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3522 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3523 if (!destType || !srcType)
3526 auto destRefinedType = destType;
3527 auto srcRefinedType = srcType;
3532 auto findFieldDeclarationRefiningFieldType =
3534 while (
auto *definingOp = value.getDefiningOp()) {
3535 bool shouldContinue =
true;
3536 TypeSwitch<Operation *>(definingOp)
3537 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3538 .Case<SubaccessOp>([&](SubaccessOp op) {
3542 .getElementTypePreservingConst()
3544 originalFieldType = originalFieldType.getConstType(
true);
3545 value = op.getInput();
3547 .Default([&](Operation *) { shouldContinue =
false; });
3548 if (!shouldContinue)
3554 auto destDeclaration =
3555 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3556 auto srcDeclaration =
3557 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3559 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3560 Value declaration) -> LogicalResult {
3561 auto *declarationBlock = declaration.getParentBlock();
3562 auto *block =
connect->getBlock();
3563 while (block && block != declarationBlock) {
3564 auto *parentOp = block->getParentOp();
3566 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3567 whenOp && !whenOp.getCondition().getType().isConst()) {
3570 <<
"assignment to 'const' type " << type
3571 <<
" is dependent on a non-'const' condition";
3573 <<
"assignment to nested 'const' member of type " << type
3574 <<
" is dependent on a non-'const' condition";
3577 block = parentOp->getBlock();
3582 auto emitSubaccessError = [&] {
3584 "assignment to non-'const' subaccess of 'const' type is disallowed");
3590 if (destType != destRefinedType)
3591 return emitSubaccessError();
3593 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3598 if (srcRefinedType.containsConst() &&
3601 if (srcType != srcRefinedType)
3602 return emitSubaccessError();
3603 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3611 auto dstType = getDest().getType();
3612 auto srcType = getSrc().getType();
3613 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3614 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3615 if (!dstBaseType || !srcBaseType) {
3616 if (dstType != srcType)
3617 return emitError(
"may not connect different non-base types");
3620 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3621 return emitError(
"analog types may not be connected");
3625 return emitError(
"type mismatch between destination ")
3626 << dstBaseType <<
" and source " << srcBaseType;
3631 return emitError(
"destination ")
3632 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3646 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3647 auto baseType = type_cast<FIRRTLBaseType>(type);
3650 if (baseType && baseType.containsAnalog())
3651 return emitError(
"analog types may not be connected");
3656 "`SameAnonTypeOperands` trait should have already rejected "
3657 "structurally non-equivalent types");
3680 for (
auto *user : getDest().getUsers()) {
3681 if (
auto conn = dyn_cast<FConnectLike>(user);
3682 conn && conn.getDest() == getDest() && conn != *
this)
3683 return emitError(
"destination reference cannot be reused by multiple "
3684 "operations, it can only capture a unique dataflow");
3688 if (
auto *op = getDest().getDefiningOp()) {
3690 if (isa<RefSubOp>(op))
3692 "destination reference cannot be a sub-element of a reference");
3693 if (isa<RefCastOp>(op))
3695 "destination reference cannot be a cast of another reference");
3703 SmallVector<SymbolRefAttr> missingLayers;
3705 auto diag = emitOpError(
"has more layer requirements than destination");
3706 auto ¬e = diag.attachNote();
3707 note <<
"additional layers required: ";
3708 interleaveComma(missingLayers, note);
3721 for (
auto *user : getDest().getUsers()) {
3722 if (
auto conn = dyn_cast<FConnectLike>(user);
3723 conn && conn.getDest() == getDest() && conn != *
this)
3724 return emitError(
"destination property cannot be reused by multiple "
3725 "operations, it can only capture a unique dataflow");
3731 void WhenOp::createElseRegion() {
3732 assert(!hasElseRegion() &&
"already has an else region");
3733 getElseRegion().push_back(
new Block());
3736 void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
3737 bool withElseRegion, std::function<
void()> thenCtor,
3738 std::function<
void()> elseCtor) {
3739 OpBuilder::InsertionGuard guard(builder);
3740 result.addOperands(condition);
3743 builder.createBlock(result.addRegion());
3748 Region *elseRegion = result.addRegion();
3749 if (withElseRegion) {
3750 builder.createBlock(elseRegion);
3761 FEnumType type = getInput().getType();
3764 auto numCases = getTags().size();
3765 auto numRegions = getNumRegions();
3766 if (numRegions != numCases)
3767 return emitOpError(
"expected ")
3768 << numRegions <<
" tags but got " << numCases;
3770 auto numTags = type.getNumElements();
3772 SmallDenseSet<int64_t> seen;
3773 for (
const auto &[tag, region] : llvm::zip(getTags(), getRegions())) {
3774 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3777 if (region.getNumArguments() != 1)
3778 return emitOpError(
"region should have exactly one argument");
3781 if (tagIndex >= numTags)
3782 return emitOpError(
"the tag index ")
3783 << tagIndex <<
" is out of the range of valid tags in " << type;
3786 auto [it, inserted] = seen.insert(tagIndex);
3788 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3789 <<
" is matched more than once";
3792 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3793 auto regionType = region.getArgument(0).getType();
3794 if (regionType != expectedType)
3795 return emitOpError(
"region type ")
3796 << regionType <<
" does not match the expected type "
3801 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3802 if (!seen.contains(i))
3803 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3808 void MatchOp::print(OpAsmPrinter &p) {
3809 auto input = getInput();
3810 FEnumType type = input.getType();
3811 auto regions = getRegions();
3812 p <<
" " << input <<
" : " << type;
3813 SmallVector<StringRef> elided = {
"tags"};
3814 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3817 for (
const auto &[tag, region] : llvm::zip(getTags(), regions)) {
3820 p.printKeywordOrString(
3821 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3823 p.printRegionArgument(region.front().getArgument(0), {},
3826 p.printRegion(region,
false);
3833 ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3834 auto *context = parser.getContext();
3835 OpAsmParser::UnresolvedOperand input;
3836 if (parser.parseOperand(input) || parser.parseColon())
3839 auto loc = parser.getCurrentLocation();
3841 if (parser.parseType(type))
3843 auto enumType = type_dyn_cast<FEnumType>(type);
3845 return parser.emitError(loc,
"expected enumeration type but got") << type;
3847 if (parser.resolveOperand(input, type, result.operands) ||
3848 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
3849 parser.parseLBrace())
3853 SmallVector<Attribute> tags;
3856 if (failed(parser.parseOptionalKeyword(
"case")))
3860 auto nameLoc = parser.getCurrentLocation();
3862 OpAsmParser::Argument arg;
3863 auto *region = result.addRegion();
3864 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
3865 parser.parseArgument(arg) || parser.parseRParen())
3869 auto index = enumType.getElementIndex(name);
3871 return parser.emitError(nameLoc,
"the tag \"")
3872 << name <<
"\" is not a member of the enumeration " << enumType;
3876 arg.type = enumType.getElementTypePreservingConst(*index);
3877 if (parser.parseRegion(*region, arg))
3882 return parser.parseRBrace();
3885 void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
3887 MutableArrayRef<std::unique_ptr<Region>> regions) {
3888 result.addOperands(input);
3889 result.addAttribute(
"tags", tags);
3890 result.addRegions(regions);
3903 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
3904 DictionaryAttr attrs, mlir::OpaqueProperties properties,
3905 RegionRange regions, SmallVectorImpl<Type> &results,
3906 llvm::function_ref<
FIRRTLType(ValueRange, ArrayRef<NamedAttribute>,
3907 std::optional<Location>)>
3909 auto type = callback(
3910 operands, attrs ? attrs.getValue() : ArrayRef<NamedAttribute>{}, loc);
3912 results.push_back(type);
3920 static Attribute
maybeGetAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3921 for (
auto attr : attrs)
3922 if (attr.getName() == name)
3923 return attr.getValue();
3929 static Attribute
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3932 llvm::report_fatal_error(
"attribute '" + name +
"' not found");
3936 template <
typename AttrClass>
3937 AttrClass
getAttr(ArrayRef<NamedAttribute> attrs, StringRef name) {
3938 return cast<AttrClass>(
getAttr(attrs, name));
3943 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
3944 bool visitInvalidExpr(Operation *op) {
return false; }
3945 bool visitUnhandledExpr(Operation *op) {
return true; }
3954 if (
auto ty = type_dyn_cast<IntType>(getType())) {
3955 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
3956 auto width = ty.getWidthOrSentinel();
3960 name = (Twine(base) + Twine(
width)).str();
3961 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
3962 auto width = ty.getWidthOrSentinel();
3964 name =
"invalid_analog";
3966 name = (
"invalid_analog" + Twine(
width)).str();
3967 }
else if (type_isa<AsyncResetType>(getType()))
3968 name =
"invalid_asyncreset";
3969 else if (type_isa<ResetType>(getType()))
3970 name =
"invalid_reset";
3971 else if (type_isa<ClockType>(getType()))
3972 name =
"invalid_clock";
3976 setNameFn(getResult(), name);
3979 void ConstantOp::print(OpAsmPrinter &p) {
3981 p.printAttributeWithoutType(getValueAttr());
3983 p.printType(getType());
3984 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
3987 ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
3990 auto loc = parser.getCurrentLocation();
3991 auto valueResult = parser.parseOptionalInteger(value);
3992 if (!valueResult.has_value())
3993 return parser.emitError(loc,
"expected integer value");
3997 if (failed(*valueResult) || parser.parseColonType(resultType) ||
3998 parser.parseOptionalAttrDict(result.attributes))
4000 result.addTypes(resultType);
4006 if (
width > value.getBitWidth()) {
4010 value = value.sext(
width);
4011 }
else if (
width < value.getBitWidth()) {
4014 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4015 : value.getActiveBits();
4016 if (
width < neededBits)
4017 return parser.emitError(loc,
"constant out of range for result type ")
4019 value = value.trunc(
width);
4023 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4025 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4026 result.addAttribute(
"value", valueAttr);
4036 "firrtl.constant attribute bitwidth doesn't match return type");
4039 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4040 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4041 return emitError(
"firrtl.constant attribute has wrong sign");
4048 void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4049 const APInt &value) {
4053 "incorrect attribute bitwidth for firrtl.constant");
4057 return build(builder, result, type, attr);
4062 void ConstantOp::build(OpBuilder &builder, OperationState &result,
4063 const APSInt &value) {
4066 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4067 return build(builder, result, type, attr);
4077 SmallString<32> specialNameBuffer;
4078 llvm::raw_svector_ostream specialName(specialNameBuffer);
4080 getValue().print(specialName, intTy.
isSigned());
4082 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4085 specialName <<
width;
4086 setNameFn(getResult(), specialName.str());
4089 void SpecialConstantOp::print(OpAsmPrinter &p) {
4092 p << static_cast<unsigned>(getValue());
4094 p.printType(getType());
4095 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4098 ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4099 OperationState &result) {
4103 auto loc = parser.getCurrentLocation();
4104 auto valueResult = parser.parseOptionalInteger(value);
4105 if (!valueResult.has_value())
4106 return parser.emitError(loc,
"expected integer value");
4109 if (value != 0 && value != 1)
4110 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4114 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4115 parser.parseOptionalAttrDict(result.attributes))
4117 result.addTypes(resultType);
4120 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4121 result.addAttribute(
"value", valueAttr);
4126 SmallString<32> specialNameBuffer;
4127 llvm::raw_svector_ostream specialName(specialNameBuffer);
4129 specialName << static_cast<unsigned>(getValue());
4130 auto type = getType();
4131 if (type_isa<ClockType>(type)) {
4132 specialName <<
"_clock";
4133 }
else if (type_isa<ResetType>(type)) {
4134 specialName <<
"_reset";
4135 }
else if (type_isa<AsyncResetType>(type)) {
4136 specialName <<
"_asyncreset";
4138 setNameFn(getResult(), specialName.str());
4145 if (type.isGround()) {
4146 if (!isa<IntegerAttr>(attr)) {
4147 op->emitOpError(
"Ground type is not an integer attribute");
4152 auto attrlist = dyn_cast<ArrayAttr>(attr);
4154 op->emitOpError(
"expected array attribute for aggregate constant");
4157 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4158 if (array.getNumElements() != attrlist.size()) {
4159 op->emitOpError(
"array attribute (")
4160 << attrlist.size() <<
") has wrong size for vector constant ("
4161 << array.getNumElements() <<
")";
4164 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4168 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4169 if (bundle.getNumElements() != attrlist.size()) {
4170 op->emitOpError(
"array attribute (")
4171 << attrlist.size() <<
") has wrong size for bundle constant ("
4172 << bundle.getNumElements() <<
")";
4175 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4176 if (bundle.getElement(i).isFlip) {
4177 op->emitOpError(
"Cannot have constant bundle type with flip");
4185 op->emitOpError(
"Unknown aggregate type");
4195 Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4197 Attribute value = getFields();
4198 while (fieldID != 0) {
4199 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4200 auto index = bundle.getIndexForFieldID(fieldID);
4201 fieldID -= bundle.getFieldID(index);
4202 type = bundle.getElementType(index);
4203 value = cast<ArrayAttr>(value)[index];
4205 auto vector = type_cast<FVectorType>(type);
4206 auto index = vector.getIndexForFieldID(fieldID);
4207 fieldID -= vector.getFieldID(index);
4208 type = vector.getElementType();
4209 value = cast<ArrayAttr>(value)[index];
4215 void FIntegerConstantOp::print(OpAsmPrinter &p) {
4217 p.printAttributeWithoutType(getValueAttr());
4218 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4221 ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4222 OperationState &result) {
4223 auto *context = parser.getContext();
4225 if (parser.parseInteger(value) ||
4226 parser.parseOptionalAttrDict(result.attributes))
4231 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4232 result.addAttribute(
"value", valueAttr);
4236 ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4237 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4240 if (parser.parseOperandList(operands) ||
4241 parser.parseOptionalAttrDict(result.attributes) ||
4242 parser.parseColonType(type))
4244 result.addTypes(type);
4246 return parser.resolveOperands(operands, type.getElementType(),
4250 void ListCreateOp::print(OpAsmPrinter &p) {
4252 p.printOperands(getElements());
4253 p.printOptionalAttrDict((*this)->getAttrs());
4254 p <<
" : " << getType();
4258 if (getElements().
empty())
4261 auto elementType = getElements().front().getType();
4262 auto listElementType = getType().getElementType();
4264 return emitOpError(
"has elements of type ")
4265 <<
elementType <<
" instead of " << listElementType;
4271 BundleType resultType = getType();
4272 if (resultType.getNumElements() != getFields().size())
4273 return emitOpError(
"number of fields doesn't match type");
4274 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4276 resultType.getElementTypePreservingConst(i),
4277 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4278 return emitOpError(
"type of element doesn't match bundle for field ")
4279 << resultType.getElement(i).name;
4285 FVectorType resultType = getType();
4286 if (resultType.getNumElements() != getFields().size())
4287 return emitOpError(
"number of fields doesn't match type");
4288 auto elemTy = resultType.getElementTypePreservingConst();
4289 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4291 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4292 return emitOpError(
"type of element doesn't match vector element");
4302 FEnumType resultType = getResult().getType();
4303 auto elementIndex = resultType.getElementIndex(
getFieldName());
4305 return emitOpError(
"label ")
4306 <<
getFieldName() <<
" is not a member of the enumeration type "
4309 resultType.getElementTypePreservingConst(*elementIndex),
4310 getInput().getType()))
4311 return emitOpError(
"type of element doesn't match enum element");
4315 void FEnumCreateOp::print(OpAsmPrinter &printer) {
4318 printer <<
'(' << getInput() <<
')';
4319 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4320 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4322 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4323 ArrayRef<Type>{getResult().getType()});
4326 ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4327 auto *context = parser.getContext();
4329 OpAsmParser::UnresolvedOperand input;
4330 std::string fieldName;
4331 mlir::FunctionType functionType;
4332 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4333 parser.parseOperand(input) || parser.parseRParen() ||
4334 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4335 parser.parseType(functionType))
4338 if (functionType.getNumInputs() != 1)
4339 return parser.emitError(parser.getNameLoc(),
"single input type required");
4340 if (functionType.getNumResults() != 1)
4341 return parser.emitError(parser.getNameLoc(),
"single result type required");
4343 auto inputType = functionType.getInput(0);
4344 if (parser.resolveOperand(input, inputType, result.operands))
4347 auto outputType = functionType.getResult(0);
4348 auto enumType = type_dyn_cast<FEnumType>(outputType);
4350 return parser.emitError(parser.getNameLoc(),
4351 "output must be enum type, got ")
4353 auto fieldIndex = enumType.getElementIndex(fieldName);
4355 return parser.emitError(parser.getNameLoc(),
4356 "unknown field " + fieldName +
" in enum type ")
4359 result.addAttribute(
4363 result.addTypes(enumType);
4373 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4374 return emitOpError(
"element index is greater than the number of fields in "
4379 void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4380 printer <<
' ' << getInput() <<
' ';
4382 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4383 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4384 printer <<
" : " << getInput().getType();
4387 ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4388 auto *context = parser.getContext();
4390 OpAsmParser::UnresolvedOperand input;
4391 std::string fieldName;
4393 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4394 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4395 parser.parseType(inputType))
4398 if (parser.resolveOperand(input, inputType, result.operands))
4401 auto enumType = type_dyn_cast<FEnumType>(inputType);
4403 return parser.emitError(parser.getNameLoc(),
4404 "input must be enum type, got ")
4406 auto fieldIndex = enumType.getElementIndex(fieldName);
4408 return parser.emitError(parser.getNameLoc(),
4409 "unknown field " + fieldName +
" in enum type ")
4412 result.addAttribute(
4421 FIRRTLType IsTagOp::inferReturnType(ValueRange operands,
4422 ArrayRef<NamedAttribute> attrs,
4423 std::optional<Location> loc) {
4425 isConst(operands[0].getType()));
4428 template <
typename OpTy>
4430 auto *context = parser.getContext();
4432 OpAsmParser::UnresolvedOperand input;
4433 std::string fieldName;
4435 if (parser.parseOperand(input) || parser.parseLSquare() ||
4436 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4437 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4438 parser.parseType(inputType))
4441 if (parser.resolveOperand(input, inputType, result.operands))
4444 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4446 return parser.emitError(parser.getNameLoc(),
4447 "input must be bundle type, got ")
4449 auto fieldIndex = bundleType.getElementIndex(fieldName);
4451 return parser.emitError(parser.getNameLoc(),
4452 "unknown field " + fieldName +
" in bundle type ")
4455 result.addAttribute(
4459 SmallVector<Type> inferredReturnTypes;
4461 result.attributes.getDictionary(context),
4462 result.getRawProperties(), result.regions,
4463 inferredReturnTypes)))
4465 result.addTypes(inferredReturnTypes);
4470 ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4471 auto *context = parser.getContext();
4473 OpAsmParser::UnresolvedOperand input;
4474 std::string fieldName;
4476 if (parser.parseOperand(input) || parser.parseLSquare() ||
4477 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4478 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4479 parser.parseType(inputType))
4482 if (parser.resolveOperand(input, inputType, result.operands))
4485 auto enumType = type_dyn_cast<FEnumType>(inputType);
4487 return parser.emitError(parser.getNameLoc(),
4488 "input must be enum type, got ")
4490 auto fieldIndex = enumType.getElementIndex(fieldName);
4492 return parser.emitError(parser.getNameLoc(),
4493 "unknown field " + fieldName +
" in enum type ")
4496 result.addAttribute(
4500 SmallVector<Type> inferredReturnTypes;
4502 context, result.location, result.operands,
4503 result.attributes.getDictionary(context), result.getRawProperties(),
4504 result.regions, inferredReturnTypes)))
4506 result.addTypes(inferredReturnTypes);
4511 ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4512 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4514 ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4515 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4518 template <
typename OpTy>
4520 printer <<
' ' << op.getInput() <<
'[';
4521 printer.printKeywordOrString(op.getFieldName());
4523 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4524 elidedAttrs.push_back(
"fieldIndex");
4525 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4526 printer <<
" : " << op.getInput().getType();
4528 void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4529 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4531 void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4532 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4535 void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4536 printer <<
' ' << getInput() <<
'[';
4539 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4540 elidedAttrs.push_back(
"fieldIndex");
4541 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4542 printer <<
" : " << getInput().getType();
4545 template <
typename OpTy>
4547 if (op.getFieldIndex() >=
4548 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4550 return op.emitOpError(
"subfield element index is greater than the number "
4551 "of fields in the bundle type");
4555 return verifySubfieldLike<SubfieldOp>(*
this);
4558 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4562 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4563 return emitOpError(
"subfield element index is greater than the number "
4564 "of fields in the bundle type");
4574 SmallVector<Operation *, 8> worklist({op});
4578 bool constant =
true;
4584 while (constant && !(worklist.empty()))
4585 TypeSwitch<Operation *>(worklist.pop_back_val())
4586 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4587 if (
auto definingOp = op.getInput().getDefiningOp())
4588 worklist.push_back(definingOp);
4591 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4592 for (
auto &use : op.getResult().getUses())
4593 worklist.push_back(use.getOwner());
4595 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4596 .Default([&](
auto) { constant =
false; });
4605 if (
auto *op = value.getDefiningOp())
4612 return emitOpError() << getInput().getType()
4613 <<
" is not 'const'-castable to "
4614 << getResult().getType();
4618 FIRRTLType SubfieldOp::inferReturnType(ValueRange operands,
4619 ArrayRef<NamedAttribute> attrs,
4620 std::optional<Location> loc) {
4621 auto inType = type_cast<BundleType>(operands[0].getType());
4623 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4625 if (fieldIndex >= inType.getNumElements())
4627 "subfield element index is greater than the "
4628 "number of fields in the bundle type");
4632 return inType.getElementTypePreservingConst(fieldIndex);
4635 FIRRTLType OpenSubfieldOp::inferReturnType(ValueRange operands,
4636 ArrayRef<NamedAttribute> attrs,
4637 std::optional<Location> loc) {
4638 auto inType = type_cast<OpenBundleType>(operands[0].getType());
4640 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4642 if (fieldIndex >= inType.getNumElements())
4644 "subfield element index is greater than the "
4645 "number of fields in the bundle type");
4649 return inType.getElementTypePreservingConst(fieldIndex);
4652 bool SubfieldOp::isFieldFlipped() {
4653 BundleType bundle = getInput().getType();
4654 return bundle.getElement(getFieldIndex()).isFlip;
4656 bool OpenSubfieldOp::isFieldFlipped() {
4657 auto bundle = getInput().getType();
4658 return bundle.getElement(getFieldIndex()).isFlip;
4661 FIRRTLType SubindexOp::inferReturnType(ValueRange operands,
4662 ArrayRef<NamedAttribute> attrs,
4663 std::optional<Location> loc) {
4664 Type inType = operands[0].getType();
4666 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4668 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4669 if (fieldIdx < vectorType.getNumElements())
4670 return vectorType.getElementTypePreservingConst();
4672 "' in vector type ", inType);
4678 FIRRTLType OpenSubindexOp::inferReturnType(ValueRange operands,
4679 ArrayRef<NamedAttribute> attrs,
4680 std::optional<Location> loc) {
4681 Type inType = operands[0].getType();
4683 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4685 if (
auto vectorType = type_dyn_cast<OpenVectorType>(inType)) {
4686 if (fieldIdx < vectorType.getNumElements())
4687 return vectorType.getElementTypePreservingConst();
4689 "' in vector type ", inType);
4695 FIRRTLType SubtagOp::inferReturnType(ValueRange operands,
4696 ArrayRef<NamedAttribute> attrs,
4697 std::optional<Location> loc) {
4698 auto inType = type_cast<FEnumType>(operands[0].getType());
4700 getAttr<IntegerAttr>(attrs,
"fieldIndex").getValue().getZExtValue();
4702 if (fieldIndex >= inType.getNumElements())
4704 "subtag element index is greater than the "
4705 "number of fields in the enum type");
4709 auto elementType = inType.getElement(fieldIndex).type;
4713 FIRRTLType SubaccessOp::inferReturnType(ValueRange operands,
4714 ArrayRef<NamedAttribute> attrs,
4715 std::optional<Location> loc) {
4716 auto inType = operands[0].getType();
4717 auto indexType = operands[1].getType();
4719 if (!type_isa<UIntType>(indexType))
4723 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4725 return vectorType.getElementTypePreservingConst();
4726 return vectorType.getElementType().getAllConstDroppedType();
4733 FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4734 ArrayRef<NamedAttribute> attrs,
4735 std::optional<Location> loc) {
4736 auto inType = type_cast<FEnumType>(operands[0].getType());
4737 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4741 ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4742 OpAsmParser::UnresolvedOperand index;
4743 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
4744 Type indexType, elemType;
4746 if (parser.parseOperand(index) || parser.parseComma() ||
4747 parser.parseOperandList(inputs) ||
4748 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4749 parser.parseType(indexType) || parser.parseComma() ||
4750 parser.parseType(elemType))
4753 if (parser.resolveOperand(index, indexType, result.operands))
4756 result.addTypes(elemType);
4758 return parser.resolveOperands(inputs, elemType, result.operands);
4761 void MultibitMuxOp::print(OpAsmPrinter &p) {
4762 p <<
" " << getIndex() <<
", ";
4763 p.printOperands(getInputs());
4764 p.printOptionalAttrDict((*this)->getAttrs());
4765 p <<
" : " << getIndex().getType() <<
", " << getType();
4768 FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4769 ArrayRef<NamedAttribute> attrs,
4770 std::optional<Location> loc) {
4771 if (operands.size() < 2)
4775 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4776 return operands[1].getType() == op.getType();
4780 return type_cast<FIRRTLType>(operands[1].getType());
4788 MLIRContext *context, std::optional<mlir::Location> location,
4789 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4790 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4791 auto type = inferReturnType(operands, attributes.getValue(), location);
4794 inferredReturnTypes.push_back(type);
4798 Type ObjectSubfieldOp::inferReturnType(ValueRange operands,
4799 ArrayRef<NamedAttribute> attrs,
4800 std::optional<Location> loc) {
4801 auto classType = dyn_cast<ClassType>(operands[0].getType());
4805 auto index = getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
4806 if (classType.getNumElements() <= index)
4808 "number of fields in the object");
4810 return classType.getElement(index).type;
4813 void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4814 auto input = getInput();
4815 auto classType = input.getType();
4816 p <<
' ' << input <<
"[";
4817 p.printKeywordOrString(classType.getElement(getIndex()).name);
4819 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4820 p <<
" : " << classType;
4823 ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4824 OperationState &result) {
4825 auto *context = parser.getContext();
4827 OpAsmParser::UnresolvedOperand input;
4828 std::string fieldName;
4829 ClassType inputType;
4830 if (parser.parseOperand(input) || parser.parseLSquare() ||
4831 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4832 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4833 parser.parseType(inputType) ||
4834 parser.resolveOperand(input, inputType, result.operands))
4837 auto index = inputType.getElementIndex(fieldName);
4839 return parser.emitError(parser.getNameLoc(),
4840 "unknown field " + fieldName +
" in class type ")
4842 result.addAttribute(
"index",
4845 SmallVector<Type> inferredReturnTypes;
4847 result.attributes.getDictionary(context),
4848 result.getRawProperties(), result.regions,
4849 inferredReturnTypes)))
4851 result.addTypes(inferredReturnTypes);
4868 int32_t &rhsWidth,
bool &isConstResult,
4869 std::optional<Location> loc) {
4871 auto lhsi = type_dyn_cast<IntType>(lhs);
4872 auto rhsi = type_dyn_cast<IntType>(rhs);
4873 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4876 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4878 else if (!lhsi && rhsi)
4879 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4881 else if (!lhsi && !rhsi)
4882 mlir::emitError(*loc,
"operands must be integer types, not ")
4883 << lhs <<
" and " << rhs;
4885 mlir::emitError(*loc,
"operand signedness must match");
4890 lhsWidth = lhsi.getWidthOrSentinel();
4891 rhsWidth = rhsi.getWidthOrSentinel();
4892 isConstResult = lhsi.isConst() && rhsi.isConst();
4897 assert(op->getNumOperands() == 2 &&
4898 "SameOperandsIntTypeKind on non-binary op");
4899 int32_t lhsWidth, rhsWidth;
4902 op->getOperand(1).getType(), lhsWidth,
4903 rhsWidth, isConstResult, op->getLoc()));
4907 ArrayRef<NamedAttribute> attrs,
4909 if (operands.size() != 2 || !attrs.empty()) {
4910 mlir::emitError(loc,
"operation requires two operands and no constants");
4917 std::optional<Location> loc) {
4918 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4919 bool isConstResult =
false;
4923 if (lhsWidth != -1 && rhsWidth != -1)
4924 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
4925 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4930 std::optional<Location> loc) {
4931 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4932 bool isConstResult =
false;
4936 if (lhsWidth != -1 && rhsWidth != -1)
4937 resultWidth = lhsWidth + rhsWidth;
4939 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4944 std::optional<Location> loc) {
4945 int32_t lhsWidth, rhsWidth;
4946 bool isConstResult =
false;
4951 if (type_isa<UIntType>(lhs))
4952 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
4955 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
4956 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
4960 std::optional<Location> loc) {
4961 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4962 bool isConstResult =
false;
4966 if (lhsWidth != -1 && rhsWidth != -1)
4967 resultWidth = std::min(lhsWidth, rhsWidth);
4968 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4973 std::optional<Location> loc) {
4974 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4975 bool isConstResult =
false;
4979 if (lhsWidth != -1 && rhsWidth != -1) {
4980 resultWidth = std::max(lhsWidth, rhsWidth);
4981 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
4984 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
4988 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
4992 std::optional<Location> loc) {
4993 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
4996 auto lhsVec = type_cast<FVectorType>(lhs);
4997 auto rhsVec = type_cast<FVectorType>(rhs);
4999 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5004 rhsVec.getElementTypePreservingConst(), loc);
5007 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5009 lhsVec.isConst() && rhsVec.isConst() &&
5010 elemBaseType.isConst());
5014 std::optional<Location> loc) {
5019 std::optional<Location> loc) {
5020 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5021 bool isConstResult =
false;
5025 if (lhsWidth != -1 && rhsWidth != -1)
5026 resultWidth = lhsWidth + rhsWidth;
5027 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5031 std::optional<Location> loc) {
5032 auto lhsi = type_dyn_cast<IntType>(lhs);
5033 auto rhsui = type_dyn_cast<UIntType>(rhs);
5034 if (!rhsui || !lhsi)
5036 loc,
"first operand should be integer, second unsigned int");
5040 auto width = lhsi.getWidthOrSentinel();
5041 if (
width == -1 || !rhsui.getWidth().has_value()) {
5044 auto amount = *rhsui.getWidth();
5047 "shift amount too large: second operand of "
5048 "dshl is wider than 31 bits");
5049 int64_t newWidth = (int64_t)
width + ((int64_t)1 << amount) - 1;
5050 if (newWidth > INT32_MAX)
5052 loc,
"shift amount too large: first operand shifted by maximum "
5053 "amount exceeds maximum width");
5057 lhsi.isConst() && rhsui.isConst());
5061 std::optional<Location> loc) {
5062 auto lhsi = type_dyn_cast<IntType>(lhs);
5063 auto rhsu = type_dyn_cast<UIntType>(rhs);
5066 loc,
"first operand should be integer, second unsigned int");
5067 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5071 std::optional<Location> loc) {
5072 auto lhsi = type_dyn_cast<IntType>(lhs);
5073 auto rhsu = type_dyn_cast<UIntType>(rhs);
5076 loc,
"first operand should be integer, second unsigned int");
5077 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5085 ArrayRef<NamedAttribute> attrs,
5087 if (operands.size() != 1 || !attrs.empty()) {
5088 mlir::emitError(loc,
"operation requires one operand and no constants");
5095 SizeOfIntrinsicOp::inferUnaryReturnType(
FIRRTLType input,
5096 std::optional<Location> loc) {
5101 std::optional<Location> loc) {
5102 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5105 int32_t
width = base.getBitWidthOrSentinel();
5112 std::optional<Location> loc) {
5113 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5116 int32_t
width = base.getBitWidthOrSentinel();
5123 AsAsyncResetPrimOp::inferUnaryReturnType(
FIRRTLType input,
5124 std::optional<Location> loc) {
5125 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5128 "operand must be single bit scalar base type");
5129 int32_t
width = base.getBitWidthOrSentinel();
5136 std::optional<Location> loc) {
5141 std::optional<Location> loc) {
5142 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5143 auto width = uiType.getWidthOrSentinel();
5149 if (type_isa<SIntType>(input))
5156 std::optional<Location> loc) {
5157 auto inputi = type_dyn_cast<IntType>(input);
5160 int32_t
width = inputi.getWidthOrSentinel();
5167 std::optional<Location> loc) {
5168 auto inputi = type_dyn_cast<IntType>(input);
5171 if (isa<UIntType>(inputi))
5173 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5178 std::optional<Location> loc) {
5186 LogicalResult BitsPrimOp::validateArguments(ValueRange operands,
5187 ArrayRef<NamedAttribute> attrs,
5189 if (operands.size() != 1 || attrs.size() != 2) {
5190 mlir::emitError(loc,
"operation requires one operand and two constants");
5196 FIRRTLType BitsPrimOp::inferReturnType(ValueRange operands,
5197 ArrayRef<NamedAttribute> attrs,
5198 std::optional<Location> loc) {
5199 auto input = operands[0].getType();
5200 auto high = getAttr<IntegerAttr>(attrs,
"hi").getValue().getSExtValue();
5201 auto low = getAttr<IntegerAttr>(attrs,
"lo").getValue().getSExtValue();
5203 auto inputi = type_dyn_cast<IntType>(input);
5206 loc,
"input type should be the int type but got ", input);
5211 loc,
"high must be equal or greater than low, but got high = ", high,
5219 int32_t
width = inputi.getWidthOrSentinel();
5223 "high must be smaller than the width of input, but got high = ", high,
5224 ", width = ",
width);
5230 ArrayRef<NamedAttribute> attrs,
5232 if (operands.size() != 1 || attrs.size() != 1) {
5233 mlir::emitError(loc,
"operation requires one operand and one constant");
5239 FIRRTLType HeadPrimOp::inferReturnType(ValueRange operands,
5240 ArrayRef<NamedAttribute> attrs,
5241 std::optional<Location> loc) {
5242 auto input = operands[0].getType();
5243 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5245 auto inputi = type_dyn_cast<IntType>(input);
5246 if (amount < 0 || !inputi)
5248 loc,
"operand must have integer type and amount must be >= 0");
5250 int32_t
width = inputi.getWidthOrSentinel();
5257 LogicalResult MuxPrimOp::validateArguments(ValueRange operands,
5258 ArrayRef<NamedAttribute> attrs,
5260 if (operands.size() != 3 || attrs.size() != 0) {
5261 mlir::emitError(loc,
"operation requires three operands and no constants");
5279 bool isConstCondition,
5280 std::optional<Location> loc) {
5286 if (high.getTypeID() != low.getTypeID())
5287 return emitInferRetTypeError<FIRRTLBaseType>(
5288 loc,
"incompatible mux operand types, true value type: ", high,
5289 ", false value type: ", low);
5291 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5296 if (type_isa<IntType>(low)) {
5301 if (highWidth == -1)
5303 return (lowWidth > highWidth ? low : high).
getConstType(outerTypeIsConst);
5307 auto highVector = type_dyn_cast<FVectorType>(high);
5308 auto lowVector = type_dyn_cast<FVectorType>(low);
5309 if (highVector && lowVector &&
5310 highVector.getNumElements() == lowVector.getNumElements()) {
5312 lowVector.getElementTypePreservingConst(),
5313 isConstCondition, loc);
5321 auto highBundle = type_dyn_cast<BundleType>(high);
5322 auto lowBundle = type_dyn_cast<BundleType>(low);
5323 if (highBundle && lowBundle) {
5324 auto highElements = highBundle.getElements();
5325 auto lowElements = lowBundle.getElements();
5328 SmallVector<BundleType::BundleElement> newElements;
5330 bool failed =
false;
5332 if (highElements[i].name != lowElements[i].name ||
5333 highElements[i].isFlip != lowElements[i].isFlip) {
5337 auto element = highElements[i];
5339 highBundle.getElementTypePreservingConst(i),
5340 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5343 newElements.push_back(element);
5346 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5348 return emitInferRetTypeError<FIRRTLBaseType>(
5349 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5350 ", false value type: ", low);
5355 return emitInferRetTypeError<FIRRTLBaseType>(
5356 loc,
"invalid mux operand types, true value type: ", high,
5357 ", false value type: ", low);
5360 FIRRTLType MuxPrimOp::inferReturnType(ValueRange operands,
5361 ArrayRef<NamedAttribute> attrs,
5362 std::optional<Location> loc) {
5363 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5364 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5365 if (!highType || !lowType)
5371 FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5372 ArrayRef<NamedAttribute> attrs,
5373 std::optional<Location> loc) {
5374 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5375 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5376 if (!highType || !lowType)
5382 FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5383 ArrayRef<NamedAttribute> attrs,
5384 std::optional<Location> loc) {
5385 SmallVector<FIRRTLBaseType> types;
5387 for (
unsigned i = 1; i < 5; i++) {
5388 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5393 isConst(operands[0].getType()), loc);
5397 result = types.back();
5403 FIRRTLType PadPrimOp::inferReturnType(ValueRange operands,
5404 ArrayRef<NamedAttribute> attrs,
5405 std::optional<Location> loc) {
5406 auto input = operands[0].getType();
5407 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5409 auto inputi = type_dyn_cast<IntType>(input);
5410 if (amount < 0 || !inputi)
5412 loc,
"pad input must be integer and amount must be >= 0");
5414 int32_t
width = inputi.getWidthOrSentinel();
5423 FIRRTLType ShlPrimOp::inferReturnType(ValueRange operands,
5424 ArrayRef<NamedAttribute> attrs,
5425 std::optional<Location> loc) {
5426 auto input = operands[0].getType();
5427 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5429 auto inputi = type_dyn_cast<IntType>(input);
5430 if (amount < 0 || !inputi)
5432 loc,
"shl input must be integer and amount must be >= 0");
5434 int32_t
width = inputi.getWidthOrSentinel();
5442 FIRRTLType ShrPrimOp::inferReturnType(ValueRange operands,
5443 ArrayRef<NamedAttribute> attrs,
5444 std::optional<Location> loc) {
5445 auto input = operands[0].getType();
5446 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5448 auto inputi = type_dyn_cast<IntType>(input);
5449 if (amount < 0 || !inputi)
5451 loc,
"shr input must be integer and amount must be >= 0");
5453 int32_t
width = inputi.getWidthOrSentinel();
5456 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5457 width = std::max<int32_t>(minWidth,
width - amount);
5464 FIRRTLType TailPrimOp::inferReturnType(ValueRange operands,
5465 ArrayRef<NamedAttribute> attrs,
5466 std::optional<Location> loc) {
5467 auto input = operands[0].getType();
5468 auto amount = getAttr<IntegerAttr>(attrs,
"amount").getValue().getSExtValue();
5470 auto inputi = type_dyn_cast<IntType>(input);
5471 if (amount < 0 || !inputi)
5473 loc,
"tail input must be integer and amount must be >= 0");
5475 int32_t
width = inputi.getWidthOrSentinel();
5479 loc,
"amount must be less than or equal operand width");
5491 function_ref<
void(Value, StringRef)> setNameFn) {
5495 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5496 auto name = getText();
5498 if (name.starts_with(
"`"))
5499 name = name.drop_front();
5500 name = name.take_while(isOkCharacter);
5502 setNameFn(getResult(), name);
5510 function_ref<
void(Value, StringRef)> setNameFn) {
5514 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5515 auto name = getText();
5517 if (name.starts_with(
"`"))
5518 name = name.drop_front();
5519 name = name.take_while(isOkCharacter);
5521 setNameFn(getResult(), name);
5532 op->emitError() <<
"unknown width is not allowed for DPI";
5533 return WalkResult::interrupt();
5537 return WalkResult::advance();
5539 <<
"integer types used by DPI functions must have a "
5540 "specific bit width; "
5541 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5542 "32(int), 64(longint) "
5543 "or greater than 64, but got "
5545 return WalkResult::interrupt();
5551 if (
auto inputNames = getInputNames()) {
5552 if (getInputs().size() != inputNames->size())
5553 return emitError() <<
"inputNames has " << inputNames->size()
5554 <<
" elements but there are " << getInputs().size()
5555 <<
" input arguments";
5557 if (
auto outputName = getOutputName())
5558 if (getNumResults() == 0)
5559 return emitError() <<
"output name is given but there is no result";
5561 auto checkType = [
this](Type type) {
5564 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5565 llvm::all_of(this->getOperandTypes(), checkType));
5568 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5569 DPICallIntrinsicOp::computeDataFlow() {
5573 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5575 for (
auto operand : getOperands()) {
5576 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5578 SmallVector<circt::FieldRef> operandFields;
5581 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5585 for (
auto result : getResults())
5588 for (
auto field : operandFields)
5601 BundleType bundleType;
5602 hw::StructType structType;
5603 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5604 structType = dyn_cast<hw::StructType>(getType());
5606 return emitError(
"result type must be a struct");
5607 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5608 structType = dyn_cast<hw::StructType>(getOperand().getType());
5610 return emitError(
"operand type must be a struct");
5612 return emitError(
"either source or result type must be a bundle type");
5615 auto firFields = bundleType.getElements();
5616 auto hwFields = structType.getElements();
5617 if (firFields.size() != hwFields.size())
5618 return emitError(
"bundle and struct have different number of fields");
5620 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5621 if (firFields[findex].name.getValue() != hwFields[findex].name)
5622 return emitError(
"field names don't match '")
5623 << firFields[findex].name.getValue() <<
"', '"
5624 << hwFields[findex].name.getValue() <<
"'";
5628 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5629 return emitError(
"size of field '")
5630 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5638 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5640 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5642 if (*inTypeBits == *resTypeBits) {
5645 return emitError(
"cannot cast non-'const' input type ")
5646 << getOperand().getType() <<
" to 'const' result type "
5650 return emitError(
"the bitwidth of input (")
5651 << *inTypeBits <<
") and result (" << *resTypeBits
5654 if (!inTypeBits.has_value())
5655 return emitError(
"bitwidth cannot be determined for input operand type ")
5656 << getInput().getType();
5657 return emitError(
"bitwidth cannot be determined for result type ")
5668 NamedAttrList &resultAttrs) {
5669 auto result = parser.parseOptionalAttrDict(resultAttrs);
5670 if (!resultAttrs.get(
"annotations"))
5671 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5677 DictionaryAttr attr,
5678 ArrayRef<StringRef> extraElides = {}) {
5679 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5681 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5682 elidedAttrs.push_back(
"annotations");
5684 elidedAttrs.push_back(
"nameKind");
5686 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5692 NamedAttrList &resultAttrs) {
5695 if (!resultAttrs.get(
"portAnnotations")) {
5696 SmallVector<Attribute, 16> portAnnotations(
5697 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5698 resultAttrs.append(
"portAnnotations",
5699 parser.getBuilder().getArrayAttr(portAnnotations));
5706 DictionaryAttr attr,
5707 ArrayRef<StringRef> extraElides = {}) {
5708 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5710 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5711 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5712 elidedAttrs.push_back(
"portAnnotations");
5721 firrtl::NameKindEnumAttr &result) {
5724 if (!parser.parseOptionalKeyword(&keyword,
5725 {
"interesting_name",
"droppable_name"})) {
5726 auto kind = symbolizeNameKindEnum(keyword);
5738 firrtl::NameKindEnumAttr attr,
5739 ArrayRef<StringRef> extraElides = {}) {
5740 if (attr.getValue() != NameKindEnum::DroppableName)
5741 p <<
" " << stringifyNameKindEnum(attr.getValue());
5749 NamedAttrList &resultAttrs) {
5757 DictionaryAttr attrs) {
5758 SmallVector<StringRef, 4> elides;
5760 elides.push_back(Forceable::getForceableAttrName());
5769 static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5774 static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5785 if (ClassType::parseInterface(parser, type))
5792 type.printInterface(p);
5800 NamedAttrList &resultAttrs) {
5801 auto result = p.parseOptionalAttrDict(resultAttrs);
5802 if (!resultAttrs.get(
"name"))
5803 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5809 DictionaryAttr attr,
5810 ArrayRef<StringRef> extraElides = {}) {
5811 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5812 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5813 elides.push_back(
"name");
5815 p.printOptionalAttrDict(op->getAttrs(), elides);
5819 NamedAttrList &resultAttrs) {
5824 DictionaryAttr attr) {
5833 DictionaryAttr attr) {
5842 DictionaryAttr attr) {
5854 if (op->getNumResults() == 1)
5855 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5856 setNameFn(op->getResult(0), nameAttr.getValue());
6081 FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6082 ArrayRef<NamedAttribute> attrs,
6083 std::optional<Location> loc) {
6084 Type inType = operands[0].getType();
6085 auto inRefType = type_dyn_cast<RefType>(inType);
6088 loc,
"ref.resolve operand must be ref type, not ", inType);
6089 return inRefType.getType();
6092 FIRRTLType RefSendOp::inferReturnType(ValueRange operands,
6093 ArrayRef<NamedAttribute> attrs,
6094 std::optional<Location> loc) {
6095 Type inType = operands[0].getType();
6096 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6099 loc,
"ref.send operand must be base type, not ", inType);
6103 FIRRTLType RefSubOp::inferReturnType(ValueRange operands,
6104 ArrayRef<NamedAttribute> attrs,
6105 std::optional<Location> loc) {
6106 auto refType = type_dyn_cast<RefType>(operands[0].getType());
6109 auto inType = refType.getType();
6111 getAttr<IntegerAttr>(attrs,
"index").getValue().getZExtValue();
6117 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6118 if (fieldIdx < vectorType.getNumElements())
6120 vectorType.getElementType().getConstType(
6121 vectorType.isConst() || vectorType.getElementType().isConst()),
6122 refType.getForceable(), refType.getLayer());
6124 "' in RefType of vector type ", refType);
6126 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6127 if (fieldIdx >= bundleType.getNumElements()) {
6129 "subfield element index is greater than "
6130 "the number of fields in the bundle type");
6132 return RefType::get(bundleType.getElement(fieldIdx).type.getConstType(
6133 bundleType.isConst() ||
6134 bundleType.getElement(fieldIdx).type.isConst()),
6135 refType.getForceable(), refType.getLayer());
6139 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6145 SmallVector<SymbolRefAttr> missingLayers;
6148 emitOpError(
"cannot discard layer requirements of input reference");
6149 auto ¬e = diag.attachNote();
6150 note <<
"discarding layer requirements: ";
6151 llvm::interleaveComma(missingLayers, note);
6160 SmallVector<SymbolRefAttr> missingLayers;
6163 emitOpError(
"ambient layers are insufficient to resolve reference");
6164 auto ¬e = diag.attachNote();
6165 note <<
"missing layer requirements: ";
6166 interleaveComma(missingLayers, note);
6172 LogicalResult RWProbeOp::verifyInnerRefs(hw::InnerRefNamespace &ns) {
6173 auto targetRef = getTarget();
6174 if (targetRef.getModule() !=
6175 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6176 return emitOpError() <<
"has non-local target";
6178 auto target = ns.lookup(targetRef);
6180 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6182 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6187 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6188 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6189 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6190 << fType <<
" instead of expected " << getType().getType();
6191 diag.attachNote(loc) <<
"target resolves here";
6196 if (target.isPort()) {
6197 auto mod = cast<FModuleLike>(target.getOp());
6198 return checkFinalType(mod.getPortType(target.getPort()),
6199 mod.getPortLocation(target.getPort()));
6201 hw::InnerSymbolOpInterface symOp =
6202 cast<hw::InnerSymbolOpInterface>(target.getOp());
6203 if (!symOp.getTargetResult())
6204 return emitOpError(
"has target that cannot be probed")
6205 .attachNote(symOp.getLoc())
6206 .append(
"target resolves here");
6208 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6209 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6210 return emitOpError(
"is not dominated by target")
6211 .attachNote(symOp.getLoc())
6212 .append(
"target here");
6213 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6221 auto layerName = getLayerName();
6222 auto *parentOp = (*this)->getParentOp();
6225 while (isa<WhenOp, MatchOp>(parentOp))
6226 parentOp = parentOp->getParentOp();
6230 auto nestedReferences = layerName.getNestedReferences();
6231 if (nestedReferences.empty()) {
6232 if (!isa<FModuleOp>(parentOp)) {
6233 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6234 "not have a 'firrtl.module' op as a parent";
6235 return diag.attachNote(parentOp->getLoc())
6236 <<
"illegal parent op defined here";
6239 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6240 if (!parentLayerBlock) {
6241 auto diag = emitOpError()
6242 <<
"has a nested layer symbol, but does not have a '"
6243 << getOperationName() <<
"' op as a parent'";
6244 return diag.attachNote(parentOp->getLoc())
6245 <<
"illegal parent op defined here";
6247 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6248 if (parentLayerBlockName.getRootReference() !=
6249 layerName.getRootReference() ||
6250 parentLayerBlockName.getNestedReferences() !=
6251 layerName.getNestedReferences().drop_back()) {
6252 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6253 return diag.attachNote(parentLayerBlock->getLoc())
6254 <<
"illegal parent layer block defined here";
6259 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6260 [&](Operation *op) -> WalkResult {
6262 if (isa<LayerBlockOp>(op))
6263 return WalkResult::skip();
6267 for (
auto operand : op->getOperands()) {
6269 if (
auto *definingOp = operand.getDefiningOp())
6270 if (getOperation()->isAncestor(definingOp))
6273 auto type = operand.getType();
6276 if (isa<PropertyType>(type)) {
6277 auto diag = emitOpError() <<
"captures a property operand";
6278 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6279 diag.attachNote(op->getLoc()) <<
"operand is used here";
6280 return WalkResult::interrupt();
6284 if (
auto baseType = type_dyn_cast<FIRRTLBaseType>(type)) {
6285 if (!baseType.isPassive()) {
6286 auto diag = emitOpError()
6287 <<
"captures an operand which is not a passive type";
6288 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6289 diag.attachNote(op->getLoc()) <<
"operand is used here";
6290 return WalkResult::interrupt();
6296 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6298 if (isa<RefDefineOp>(
connect))
6299 return WalkResult::advance();
6303 if (
auto *destOp = dest.getDefiningOp())
6305 return WalkResult::advance();
6309 <<
"connects to a destination which is defined outside its "
6310 "enclosing layer block";
6311 diag.attachNote(getLoc()) <<
"enclosing layer block is defined here";
6312 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6313 return WalkResult::interrupt();
6316 return WalkResult::advance();
6319 return failure(result.wasInterrupted());
6323 LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6325 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6327 return emitOpError(
"invalid symbol reference");
6338 #define GET_OP_CLASSES
6339 #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).
const char * toString(Flow flow)
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)
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 bool isTypeAllowedForDPI(Operation *op, Type type)
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)
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
This class represents a reference to a specific field or element of an aggregate value.
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
ExprVisitor is a visitor for FIRRTL expression nodes.
ResultType dispatchExprVisitor(Operation *op, ExtraArgs... args)
FIRRTLBaseType 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.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
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)
static LogicalResult verify(Value clock, bool eventExists, mlir::Location loc)
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.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool 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.