27#include "mlir/IR/BuiltinTypes.h"
28#include "mlir/IR/Diagnostics.h"
29#include "mlir/IR/DialectImplementation.h"
30#include "mlir/IR/PatternMatch.h"
31#include "mlir/IR/SymbolTable.h"
32#include "mlir/Interfaces/FunctionImplementation.h"
33#include "llvm/ADT/BitVector.h"
34#include "llvm/ADT/DenseMap.h"
35#include "llvm/ADT/DenseSet.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallSet.h"
38#include "llvm/ADT/StringExtras.h"
39#include "llvm/ADT/TypeSwitch.h"
40#include "llvm/Support/FormatVariadic.h"
42using llvm::SmallDenseSet;
43using mlir::RegionRange;
45using namespace firrtl;
46using namespace chirrtl;
57 const llvm::BitVector &indicesToDrop) {
60 int lastIndex = indicesToDrop.find_last();
62 assert((
size_t)lastIndex < input.size() &&
"index out of range");
72 size_t lastCopied = 0;
73 SmallVector<T> result;
74 result.reserve(input.size() - indicesToDrop.count());
76 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
78 if (indexToDrop > lastCopied) {
79 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
80 lastCopied = indexToDrop;
87 if (lastCopied < input.size())
88 result.append(input.begin() + lastCopied, input.end());
94template <
typename RetTy =
FIRRTLType,
typename... Args>
96 const Twine &message, Args &&...args) {
98 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
104 while (Operation *op = val.getDefiningOp()) {
106 TypeSwitch<Operation *, std::optional<bool>>(op)
107 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
111 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
112 .Default([](
auto) {
return false; });
119SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
120MemOp::computeDataFlow() {
123 if (getReadLatency() > 0)
125 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
127 for (
auto memPort : getResults())
128 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
129 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
130 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
131 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
133 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
134 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
136 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
137 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
144 constexpr unsigned int addr = 1 << 0;
145 constexpr unsigned int en = 1 << 1;
146 constexpr unsigned int clk = 1 << 2;
147 constexpr unsigned int data = 1 << 3;
148 constexpr unsigned int mask = 1 << 4;
149 constexpr unsigned int rdata = 1 << 5;
150 constexpr unsigned int wdata = 1 << 6;
151 constexpr unsigned int wmask = 1 << 7;
152 constexpr unsigned int wmode = 1 << 8;
153 constexpr unsigned int def = 1 << 9;
155 auto portType = type_dyn_cast<BundleType>(type);
157 return MemOp::PortKind::Debug;
160 for (
auto elem : portType.getElements()) {
161 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
167 .Case(
"rdata",
rdata)
168 .Case(
"wdata",
wdata)
169 .Case(
"wmask",
wmask)
170 .Case(
"wmode",
wmode)
174 return MemOp::PortKind::Read;
176 return MemOp::PortKind::Write;
178 return MemOp::PortKind::ReadWrite;
179 return MemOp::PortKind::Debug;
194 llvm_unreachable(
"Unsupported Flow type.");
202 return "source flow";
206 return "duplex flow";
209 llvm_unreachable(
"Unsupported Flow type.");
214 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
215 auto *op = val.getParentBlock()->getParentOp();
216 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
217 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
218 if (direction == Direction::Out)
221 return accumulatedFlow;
224 Operation *op = val.getDefiningOp();
226 return TypeSwitch<Operation *, Flow>(op)
227 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
228 return foldFlow(op.getInput(), op.isFieldFlipped()
232 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
233 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
235 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
236 [](
auto) {
return Flow::Duplex; })
237 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
238 auto resultNo = cast<OpResult>(val).getResultNumber();
239 if (inst.getPortDirection(resultNo) == Direction::Out)
240 return accumulatedFlow;
243 .Case<MemOp>([&](
auto op) {
245 if (type_isa<RefType>(val.getType()))
249 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
250 auto input = op.getInput();
251 auto *inputOp = input.getDefiningOp();
254 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
255 auto classType = input.getType();
256 auto direction = classType.getElement(op.getIndex()).direction;
257 if (direction == Direction::In)
268 auto classType = input.getType();
269 auto direction = classType.getElement(op.getIndex()).direction;
270 if (direction == Direction::In)
273 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
275 input = op.getInput();
276 inputOp = input.getDefiningOp();
280 return accumulatedFlow;
284 .Default([&](
auto) {
return accumulatedFlow; });
290 Operation *op = val.getDefiningOp();
292 return DeclKind::Port;
294 return TypeSwitch<Operation *, DeclKind>(op)
295 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
296 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
298 .Default([](
auto) {
return DeclKind::Other; });
302 if (
auto module = dyn_cast<FModuleLike>(op))
303 return module.getNumPorts();
304 return op->getNumResults();
318 if (
auto *op = value.getDefiningOp())
320 auto arg = dyn_cast<BlockArgument>(value);
321 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
324 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
331 OpAsmSetValueNameFn setNameFn) {
335 auto *block = ®ion.front();
338 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
340 if (!argAttr || argAttr.size() != block->getNumArguments())
343 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
344 auto str = cast<StringAttr>(argAttr[i]).getValue();
346 setNameFn(block->getArgument(i), str);
352 firrtl::NameKindEnumAttr &result);
359struct CompareSymbolRefAttr {
361 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
362 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
367 auto lhsNested = lhs.getNestedReferences();
368 auto rhsNested = rhs.getNestedReferences();
369 auto lhsNestedSize = lhsNested.size();
370 auto rhsNestedSize = rhsNested.size();
371 auto e = std::min(lhsNestedSize, rhsNestedSize);
372 for (
unsigned i = 0; i < e; ++i) {
373 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].getAttr());
379 return lhsNestedSize < rhsNestedSize;
391 for (; op !=
nullptr; op = op->getParentOp()) {
392 if (
auto module = dyn_cast<FModuleLike>(op)) {
393 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
394 result.insert(layers.begin(), layers.end());
397 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
398 result.insert(layerblock.getLayerName());
416 if (
auto type = dyn_cast<RefType>(value.getType()))
417 if (
auto layer = type.getLayer())
418 result.insert(type.getLayer());
427 mlir::SymbolRefAttr dstLayer) {
437 if (srcLayer.getRootReference() != dstLayer.getRootReference())
440 auto srcNames = srcLayer.getNestedReferences();
441 auto dstNames = dstLayer.getNestedReferences();
442 if (dstNames.size() < srcNames.size())
445 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
446 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
453 if (dstLayers.contains(srcLayer))
458 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
467 SmallVectorImpl<SymbolRefAttr> &missing) {
468 for (
auto srcLayer : src)
470 missing.push_back(srcLayer);
472 llvm::sort(missing, CompareSymbolRefAttr());
473 return missing.empty();
480void CircuitOp::build(OpBuilder &builder, OperationState &result,
481 StringAttr name, ArrayAttr annotations) {
483 result.getOrAddProperties<Properties>().setName(name);
486 annotations = builder.getArrayAttr({});
487 result.getOrAddProperties<Properties>().setAnnotations(annotations);
490 Region *bodyRegion = result.addRegion();
492 bodyRegion->push_back(body);
496 NamedAttrList &resultAttrs) {
497 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
498 if (!resultAttrs.get(
"annotations"))
499 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
505 DictionaryAttr attr) {
507 SmallVector<StringRef> elidedAttrs = {
"name"};
509 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
510 if (annotationsAttr.empty())
511 elidedAttrs.push_back(
"annotations");
513 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
516LogicalResult CircuitOp::verifyRegions() {
521 emitOpError(
"must have a non-empty name");
525 mlir::SymbolTable symtbl(getOperation());
527 auto *mainModule = symtbl.lookup(
main);
529 return emitOpError().append(
530 "does not contain module with same name as circuit");
531 if (!isa<FModuleLike>(mainModule))
532 return mainModule->emitError(
533 "entity with name of circuit must be a module");
534 if (symtbl.getSymbolVisibility(mainModule) !=
535 mlir::SymbolTable::Visibility::Public)
536 return mainModule->emitError(
"main module must be public");
541 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
543 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
547 auto defname = extModule.getDefnameAttr();
553 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
554 return extModule.emitOpError()
555 .append(
"attribute 'defname' with value ", defname,
556 " conflicts with the name of another module in the circuit")
557 .attachNote(collidingModule.getLoc())
558 .append(
"previous module declared here");
566 FExtModuleOp collidingExtModule;
567 if (
auto &value = defnameMap[defname]) {
568 collidingExtModule = value;
569 if (!value.getParameters().empty() && extModule.getParameters().empty())
579 SmallVector<PortInfo> ports = extModule.getPorts();
580 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
582 if (ports.size() != collidingPorts.size())
583 return extModule.emitOpError()
584 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
585 " ports which is different from a previously defined "
586 "extmodule with the same 'defname' which has ",
587 collidingPorts.size(),
" ports")
588 .attachNote(collidingExtModule.getLoc())
589 .append(
"previous extmodule definition occurred here");
595 for (
auto p :
llvm::zip(ports, collidingPorts)) {
596 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
597 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
600 return extModule.emitOpError()
601 .append(
"with 'defname' attribute ", defname,
602 " has a port with name ", aName,
603 " which does not match the name of the port in the same "
604 "position of a previously defined extmodule with the same "
605 "'defname', expected port to have name ",
607 .attachNote(collidingExtModule.getLoc())
608 .append(
"previous extmodule definition occurred here");
610 if (!extModule.getParameters().empty() ||
611 !collidingExtModule.getParameters().empty()) {
613 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
614 aType = base.getWidthlessType();
615 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
616 bType = base.getWidthlessType();
619 return extModule.emitOpError()
620 .append(
"with 'defname' attribute ", defname,
621 " has a port with name ", aName,
622 " which has a different type ", aType,
623 " which does not match the type of the port in the same "
624 "position of a previously defined extmodule with the same "
625 "'defname', expected port to have type ",
627 .attachNote(collidingExtModule.getLoc())
628 .append(
"previous extmodule definition occurred here");
633 SmallVector<FModuleOp, 1> dutModules;
636 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
638 dutModules.push_back(moduleOp);
643 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
644 if (verifyExtModule(extModule).failed())
650 if (dutModules.size() > 1) {
651 auto diag = dutModules[0]->emitOpError()
652 <<
"is annotated as the design-under-test (DUT), but other "
653 "modules are also annotated";
654 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
655 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
662Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
669 SmallVector<PortInfo> results;
670 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
671 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
672 module.getPortDirection(i), module.getPortSymbolAttr(i),
673 module.getPortLocation(i),
674 AnnotationSet::forPort(module, i)});
679SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
681SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
683SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
685SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
688 if (dir == Direction::In)
689 return hw::ModulePort::Direction::Input;
690 if (dir == Direction::Out)
691 return hw::ModulePort::Direction::Output;
692 assert(0 &&
"invalid direction");
697 SmallVector<hw::PortInfo> results;
698 auto aname = StringAttr::get(module.getContext(),
699 hw::HWModuleLike::getPortSymbolAttrName());
700 auto emptyDict = DictionaryAttr::get(module.getContext());
701 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
702 auto sym =
module.getPortSymbolAttr(i);
704 {{
module.getPortNameAttr(i), module.getPortType(i),
705 dirFtoH(module.getPortDirection(i))},
707 sym ? DictionaryAttr::get(
709 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
711 module.getPortLocation(i)});
716SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
717 return ::getPortListImpl(*
this);
720SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
721 return ::getPortListImpl(*
this);
724SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
725 return ::getPortListImpl(*
this);
728SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
729 return ::getPortListImpl(*
this);
733 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
734 dirFtoH(module.getPortDirection(idx))},
738 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
739 StringAttr::get(module.getContext(),
740 hw::HWModuleLike::getPortSymbolAttrName()),
741 module.getPortSymbolAttr(idx)}}),
742 module.getPortLocation(idx)};
746 return ::getPortImpl(*
this, idx);
750 return ::getPortImpl(*
this, idx);
754 return ::getPortImpl(*
this, idx);
758 return ::getPortImpl(*
this, idx);
762BlockArgument FModuleOp::getArgument(
size_t portNumber) {
770 ArrayRef<std::pair<unsigned, PortInfo>> ports,
771 bool supportsInternalPaths =
false) {
774 unsigned oldNumArgs = op.getNumPorts();
775 unsigned newNumArgs = oldNumArgs + ports.size();
778 auto existingDirections = op.getPortDirectionsAttr();
779 ArrayRef<Attribute> existingNames = op.getPortNames();
780 ArrayRef<Attribute> existingTypes = op.getPortTypes();
781 ArrayRef<Attribute> existingLocs = op.getPortLocations();
782 assert(existingDirections.size() == oldNumArgs);
783 assert(existingNames.size() == oldNumArgs);
784 assert(existingTypes.size() == oldNumArgs);
785 assert(existingLocs.size() == oldNumArgs);
786 SmallVector<Attribute> internalPaths;
787 auto emptyInternalPath = InternalPathAttr::get(op.getContext());
788 if (supportsInternalPaths) {
789 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
790 llvm::append_range(internalPaths, internalPathsAttr);
792 internalPaths.resize(oldNumArgs, emptyInternalPath);
793 assert(internalPaths.size() == oldNumArgs);
796 SmallVector<bool> newDirections;
797 SmallVector<Attribute> newNames, newTypes, newAnnos, newSyms, newLocs,
799 newDirections.reserve(newNumArgs);
800 newNames.reserve(newNumArgs);
801 newTypes.reserve(newNumArgs);
802 newAnnos.reserve(newNumArgs);
803 newSyms.reserve(newNumArgs);
804 newLocs.reserve(newNumArgs);
805 newInternalPaths.reserve(newNumArgs);
807 auto emptyArray = ArrayAttr::get(op.getContext(), {});
810 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
811 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
812 newDirections.push_back(existingDirections[oldIdx]);
813 newNames.push_back(existingNames[oldIdx]);
814 newTypes.push_back(existingTypes[oldIdx]);
815 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
816 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
817 newLocs.push_back(existingLocs[oldIdx]);
818 if (supportsInternalPaths)
819 newInternalPaths.push_back(internalPaths[oldIdx]);
823 for (
auto pair : llvm::enumerate(ports)) {
824 auto idx = pair.value().first;
825 auto &port = pair.value().second;
826 migrateOldPorts(idx);
828 newNames.push_back(port.name);
829 newTypes.push_back(TypeAttr::get(port.type));
830 auto annos = port.annotations.getArrayAttr();
831 newAnnos.push_back(annos ? annos : emptyArray);
832 newSyms.push_back(port.sym);
833 newLocs.push_back(port.loc);
834 if (supportsInternalPaths)
835 newInternalPaths.push_back(emptyInternalPath);
837 migrateOldPorts(oldNumArgs);
841 if (llvm::all_of(newAnnos, [](Attribute attr) {
842 return cast<ArrayAttr>(attr).empty();
847 op->setAttr(
"portDirections",
849 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
850 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
851 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
852 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
853 op.setPortSymbols(newSyms);
854 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
855 if (supportsInternalPaths) {
857 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
858 return !cast<InternalPathAttr>(attr).getPath();
861 op->removeAttr(
"internalPaths");
863 op->setAttr(
"internalPaths",
864 ArrayAttr::get(op.getContext(), newInternalPaths));
869static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
870 if (portIndices.none())
874 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
875 ArrayRef<Attribute> portNames = op.getPortNames();
876 ArrayRef<Attribute> portTypes = op.getPortTypes();
877 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
878 ArrayRef<Attribute> portSyms = op.getPortSymbols();
879 ArrayRef<Attribute> portLocs = op.getPortLocations();
880 auto numPorts = op.getNumPorts();
882 assert(portDirections.size() == numPorts);
883 assert(portNames.size() == numPorts);
884 assert(portAnnos.size() == numPorts || portAnnos.empty());
885 assert(portTypes.size() == numPorts);
886 assert(portSyms.size() == numPorts || portSyms.empty());
887 assert(portLocs.size() == numPorts);
889 SmallVector<bool> newPortDirections =
890 removeElementsAtIndices<bool>(portDirections, portIndices);
891 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
898 op->setAttr(
"portDirections",
900 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
901 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
902 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
903 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
904 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
905 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
869static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
…}
911 auto internalPaths = op.getInternalPaths();
919 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
920 return !cast<InternalPathAttr>(attr).getPath();
923 op.removeInternalPathsAttr();
925 op.setInternalPathsAttr(ArrayAttr::get(op.getContext(), newPaths));
928void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
929 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
933void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
934 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
938void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
939 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
942void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
943 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
950void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
955 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
958 auto &[index, port] = ports[i];
959 body->insertArgument(index + i, port.type, port.loc);
963void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
968void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
976void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
980template <
typename OpTy>
982 StringAttr name, ArrayRef<PortInfo> ports) {
984 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
985 properties.setSymName(name);
988 SmallVector<Direction, 4> portDirections;
989 SmallVector<Attribute, 4> portNames;
990 SmallVector<Attribute, 4> portTypes;
991 SmallVector<Attribute, 4> portSyms;
992 SmallVector<Attribute, 4> portLocs;
993 for (
const auto &port : ports) {
994 portDirections.push_back(port.direction);
995 portNames.push_back(port.name);
996 portTypes.push_back(TypeAttr::get(port.type));
997 portSyms.push_back(port.sym);
998 portLocs.push_back(port.loc);
1001 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1004 properties.setPortDirections(
1006 properties.setPortNames(builder.getArrayAttr(portNames));
1007 properties.setPortTypes(builder.getArrayAttr(portTypes));
1008 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1009 properties.setPortLocations(builder.getArrayAttr(portLocs));
1014template <
typename OpTy>
1016 StringAttr name, ArrayRef<PortInfo> ports,
1017 ArrayAttr annotations, ArrayAttr layers) {
1018 buildModuleLike<OpTy>(builder, result, name, ports);
1019 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1022 annotations = builder.getArrayAttr({});
1023 properties.setAnnotations(annotations);
1027 SmallVector<Attribute, 4> portAnnotations;
1028 for (
const auto &port : ports)
1029 portAnnotations.push_back(port.annotations.getArrayAttr());
1030 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1031 return cast<ArrayAttr>(attr).empty();
1033 portAnnotations.clear();
1034 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1038 layers = builder.getArrayAttr({});
1039 properties.setLayers(layers);
1042template <
typename OpTy>
1043static void buildClass(OpBuilder &builder, OperationState &result,
1044 StringAttr name, ArrayRef<PortInfo> ports) {
1045 return buildModuleLike<OpTy>(builder, result, name, ports);
1048void FModuleOp::build(OpBuilder &builder, OperationState &result,
1049 StringAttr name, ConventionAttr convention,
1050 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1052 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1053 auto &properties = result.getOrAddProperties<Properties>();
1054 properties.setConvention(convention);
1057 auto *bodyRegion = result.regions[0].get();
1059 bodyRegion->push_back(body);
1062 for (
auto &elt : ports)
1063 body->addArgument(elt.type, elt.loc);
1066void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1067 StringAttr name, ConventionAttr convention,
1068 ArrayRef<PortInfo> ports, StringRef defnameAttr,
1069 ArrayAttr annotations, ArrayAttr parameters,
1070 ArrayAttr internalPaths, ArrayAttr layers) {
1071 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1072 auto &properties = result.getOrAddProperties<Properties>();
1073 properties.setConvention(convention);
1074 if (!defnameAttr.empty())
1075 properties.setDefname(builder.getStringAttr(defnameAttr));
1077 parameters = builder.getArrayAttr({});
1078 properties.setParameters(parameters);
1079 if (internalPaths && !internalPaths.empty())
1080 properties.setInternalPaths(internalPaths);
1083void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1084 StringAttr name, ArrayRef<PortInfo> ports,
1085 StringRef intrinsicNameStr, ArrayAttr annotations,
1086 ArrayAttr parameters, ArrayAttr internalPaths,
1088 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1089 auto &properties = result.getOrAddProperties<Properties>();
1090 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1092 parameters = builder.getArrayAttr({});
1093 properties.setParameters(parameters);
1094 if (internalPaths && !internalPaths.empty())
1095 properties.setInternalPaths(internalPaths);
1098void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1099 StringAttr name, ArrayRef<PortInfo> ports,
1100 uint32_t numReadPorts, uint32_t numWritePorts,
1101 uint32_t numReadWritePorts, uint32_t dataWidth,
1102 uint32_t maskBits, uint32_t readLatency,
1103 uint32_t writeLatency, uint64_t depth,
1104 ArrayAttr annotations, ArrayAttr layers) {
1105 auto *context = builder.getContext();
1106 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1107 auto ui32Type = IntegerType::get(context, 32, IntegerType::Unsigned);
1108 auto ui64Type = IntegerType::get(context, 64, IntegerType::Unsigned);
1109 auto &properties = result.getOrAddProperties<Properties>();
1110 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1111 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1112 properties.setNumReadWritePorts(
1113 IntegerAttr::get(ui32Type, numReadWritePorts));
1114 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1115 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1116 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1117 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1118 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1119 properties.setExtraPorts(ArrayAttr::get(context, {}));
1136 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1137 ArrayRef<Attribute> portAnnotations,
1138 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs) {
1141 bool printedNamesDontMatch =
false;
1143 mlir::OpPrintingFlags flags;
1147 SmallString<32> resultNameStr;
1149 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1160 resultNameStr.clear();
1161 llvm::raw_svector_ostream tmpStream(resultNameStr);
1162 p.printOperand(block->getArgument(i), tmpStream);
1165 auto portName = cast<StringAttr>(portNames[i]).getValue();
1166 if (tmpStream.str().drop_front() != portName)
1167 printedNamesDontMatch =
true;
1168 p << tmpStream.str();
1170 p.printKeywordOrString(cast<StringAttr>(portNames[i]).getValue());
1175 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1176 p.printType(portType);
1179 if (!portSyms.empty()) {
1180 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1182 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1188 if (!portAnnotations.empty() &&
1189 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1191 p.printAttribute(portAnnotations[i]);
1198 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1199 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1203 return printedNamesDontMatch;
1210 bool supportsSymbols,
1211 SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1212 SmallVectorImpl<Direction> &portDirections,
1213 SmallVectorImpl<Attribute> &portNames,
1214 SmallVectorImpl<Attribute> &portTypes,
1215 SmallVectorImpl<Attribute> &portAnnotations,
1216 SmallVectorImpl<Attribute> &portSyms,
1217 SmallVectorImpl<Attribute> &portLocs) {
1218 auto *context = parser.getContext();
1220 auto parseArgument = [&]() -> ParseResult {
1222 if (succeeded(parser.parseOptionalKeyword(
"out")))
1223 portDirections.push_back(Direction::Out);
1224 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
1225 portDirections.push_back(Direction::In);
1233 if (hasSSAIdentifiers) {
1234 OpAsmParser::Argument arg;
1235 if (parser.parseArgument(arg))
1237 entryArgs.push_back(arg);
1241 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1242 "Unknown MLIR name");
1243 if (
isdigit(arg.ssaName.name[1]))
1244 portNames.push_back(StringAttr::get(context,
""));
1246 portNames.push_back(
1247 StringAttr::get(context, arg.ssaName.name.drop_front()));
1250 irLoc = arg.ssaName.location;
1254 irLoc = parser.getCurrentLocation();
1255 std::string portName;
1256 if (parser.parseKeywordOrString(&portName))
1258 portNames.push_back(StringAttr::get(context, portName));
1263 if (parser.parseColonType(portType))
1265 portTypes.push_back(TypeAttr::get(portType));
1267 if (hasSSAIdentifiers)
1268 entryArgs.back().type = portType;
1271 if (supportsSymbols) {
1272 hw::InnerSymAttr innerSymAttr;
1273 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1274 NamedAttrList dummyAttrs;
1275 if (parser.parseCustomAttributeWithFallback(
1276 innerSymAttr, ::mlir::Type{},
1278 return ::mlir::failure();
1281 portSyms.push_back(innerSymAttr);
1286 auto parseResult = parser.parseOptionalAttribute(annos);
1287 if (!parseResult.has_value())
1288 annos = parser.getBuilder().getArrayAttr({});
1289 else if (failed(*parseResult))
1291 portAnnotations.push_back(annos);
1294 std::optional<Location> maybeLoc;
1295 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1297 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1298 portLocs.push_back(loc);
1299 if (hasSSAIdentifiers)
1300 entryArgs.back().sourceLoc = loc;
1306 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1312 ArrayAttr parameters) {
1313 if (!parameters || parameters.empty())
1317 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1318 auto paramAttr = cast<ParamDeclAttr>(param);
1319 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1320 if (
auto value = paramAttr.getValue()) {
1322 p.printAttributeWithoutType(value);
1332 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1333 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1334 p << visibility.getValue() <<
' ';
1337 p.printSymbolName(op.getModuleName());
1344 Block *body =
nullptr;
1345 if (!op->getRegion(0).empty())
1346 body = &op->getRegion(0).front();
1349 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1350 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations());
1352 SmallVector<StringRef, 12> omittedAttrs = {
1353 "sym_name",
"portDirections",
"portTypes",
"portAnnotations",
1354 "portSymbols",
"portLocations",
"parameters", visibilityAttrName};
1356 if (op.getConvention() == Convention::Internal)
1357 omittedAttrs.push_back(
"convention");
1361 if (!needPortNamesAttr)
1362 omittedAttrs.push_back(
"portNames");
1365 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1366 omittedAttrs.push_back(
"annotations");
1369 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1371 omittedAttrs.push_back(
"layers");
1373 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1382void FModuleOp::print(OpAsmPrinter &p) {
1388 Region &fbody = getBody();
1389 if (!fbody.empty()) {
1391 p.printRegion(fbody,
false,
1403 SmallVectorImpl<Attribute> ¶meters) {
1405 return parser.parseCommaSeparatedList(
1406 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1411 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1415 if (succeeded(parser.parseOptionalEqual())) {
1416 if (parser.parseAttribute(value, type))
1420 auto &builder = parser.getBuilder();
1421 parameters.push_back(ParamDeclAttr::get(
1422 builder.getContext(), builder.getStringAttr(name), type, value));
1429 ArrayAttr ¶meters) {
1430 SmallVector<Attribute> parseParameters;
1434 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1439template <
typename Properties,
typename =
void>
1442template <
typename Properties>
1444 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1445 : std::true_type {};
1447template <
typename OpTy>
1449 OperationState &result,
1450 bool hasSSAIdentifiers) {
1451 auto *context = result.getContext();
1452 auto &builder = parser.getBuilder();
1453 using Properties =
typename OpTy::Properties;
1454 auto &properties = result.getOrAddProperties<Properties>();
1458 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1461 StringAttr nameAttr;
1462 if (parser.parseSymbolName(nameAttr))
1464 properties.setSymName(nameAttr);
1468 SmallVector<Attribute, 4> parameters;
1471 properties.setParameters(builder.getArrayAttr(parameters));
1475 SmallVector<OpAsmParser::Argument> entryArgs;
1476 SmallVector<Direction, 4> portDirections;
1477 SmallVector<Attribute, 4> portNames;
1478 SmallVector<Attribute, 4> portTypes;
1479 SmallVector<Attribute, 4> portAnnotations;
1480 SmallVector<Attribute, 4> portSyms;
1481 SmallVector<Attribute, 4> portLocs;
1483 entryArgs, portDirections, portNames, portTypes,
1484 portAnnotations, portSyms, portLocs))
1488 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1491 assert(portNames.size() == portTypes.size());
1497 properties.setPortDirections(
1501 properties.setPortNames(builder.getArrayAttr(portNames));
1504 properties.setPortTypes(ArrayAttr::get(context, portTypes));
1508 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1509 return !cast<ArrayAttr>(anno).empty();
1511 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
1513 properties.setPortAnnotations(builder.getArrayAttr({}));
1516 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1517 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1520 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1523 properties.setAnnotations(builder.getArrayAttr({}));
1526 auto *body = result.addRegion();
1528 if (hasSSAIdentifiers) {
1529 if (parser.parseRegion(*body, entryArgs))
1532 body->push_back(
new Block());
1537ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1538 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1541 auto &properties = result.getOrAddProperties<Properties>();
1542 properties.setConvention(
1543 ConventionAttr::get(result.getContext(), Convention::Internal));
1544 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1548ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1549 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1552 auto &properties = result.getOrAddProperties<Properties>();
1553 properties.setConvention(
1554 ConventionAttr::get(result.getContext(), Convention::Internal));
1558ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1559 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1563ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1564 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1568LogicalResult FModuleOp::verify() {
1571 auto portTypes = getPortTypes();
1572 auto portLocs = getPortLocations();
1573 auto numPorts = portTypes.size();
1576 if (body->getNumArguments() != numPorts)
1577 return emitOpError(
"entry block must have ")
1578 << numPorts <<
" arguments to match module signature";
1581 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1582 if (arg.getType() != cast<TypeAttr>(type).getValue())
1583 return emitOpError(
"block argument types should match signature types");
1584 if (arg.getLoc() != cast<LocationAttr>(loc))
1586 "block argument locations should match signature locations");
1594 std::optional<::mlir::ArrayAttr> internalPaths) {
1599 if (internalPaths->size() != op.getNumPorts())
1600 return op.emitError(
"module has inconsistent internal path array with ")
1601 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1605 for (
auto [idx, path, typeattr] : llvm::enumerate(
1606 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1607 if (path.getPath() &&
1608 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1610 op.emitError(
"module has internal path for non-ref-type port ")
1611 << op.getPortNameAttr(idx);
1612 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1619LogicalResult FExtModuleOp::verify() {
1623 auto params = getParameters();
1627 auto checkParmValue = [&](Attribute elt) ->
bool {
1628 auto param = cast<ParamDeclAttr>(elt);
1629 auto value = param.getValue();
1630 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1632 emitError() <<
"has unknown extmodule parameter value '"
1633 << param.getName().getValue() <<
"' = " << value;
1637 if (!llvm::all_of(params, checkParmValue))
1643LogicalResult FIntModuleOp::verify() {
1647 auto params = getParameters();
1651 auto checkParmValue = [&](Attribute elt) ->
bool {
1652 auto param = cast<ParamDeclAttr>(elt);
1653 auto value = param.getValue();
1654 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1656 emitError() <<
"has unknown intmodule parameter value '"
1657 << param.getName().getValue() <<
"' = " << value;
1661 if (!llvm::all_of(params, checkParmValue))
1668 CircuitOp circuitOp,
1669 SymbolTableCollection &symbolTable,
1671 auto layer = refType.getLayer();
1674 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1676 return emitError(loc) << start <<
" associated with layer '" << layer
1677 <<
"', but this layer was not defined";
1678 if (!isa<LayerOp>(layerOp)) {
1679 auto diag = emitError(loc)
1680 << start <<
" associated with layer '" << layer
1681 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1682 << LayerOp::getOperationName() <<
"' op";
1683 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1689 SymbolTableCollection &symbolTable) {
1691 auto circuitOp =
module->getParentOfType<CircuitOp>();
1692 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1693 auto type =
module.getPortType(i);
1695 if (
auto refType = type_dyn_cast<RefType>(type)) {
1697 refType, module.getPortLocation(i), circuitOp, symbolTable,
1698 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1703 if (
auto classType = dyn_cast<ClassType>(type)) {
1704 auto className = classType.getNameAttr();
1705 auto classOp = dyn_cast_or_null<ClassLike>(
1706 symbolTable.lookupSymbolIn(circuitOp, className));
1708 return module.emitOpError() << "references unknown class " << className;
1711 if (failed(classOp.verifyType(classType,
1712 [&]() { return module.emitOpError(); })))
1721LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1726 auto circuitOp = (*this)->getParentOfType<CircuitOp>();
1727 for (
auto layer : getLayers()) {
1728 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1729 return emitOpError() <<
"enables unknown layer '" << layer <<
"'";
1736FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1741FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1746FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1750void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1755void FExtModuleOp::getAsmBlockArgumentNames(
1760void FIntModuleOp::getAsmBlockArgumentNames(
1765void FMemModuleOp::getAsmBlockArgumentNames(
1770ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1772ArrayAttr FModuleOp::getParameters() {
return {}; }
1774Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1776ConventionAttr FIntModuleOp::getConventionAttr() {
1777 return ConventionAttr::get(getContext(), getConvention());
1780Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1782ConventionAttr FMemModuleOp::getConventionAttr() {
1783 return ConventionAttr::get(getContext(), getConvention());
1791 ClassLike classOp, ClassType type,
1792 function_ref<InFlightDiagnostic()> emitError) {
1794 auto name = type.getNameAttr().getAttr();
1795 auto expectedName = classOp.getModuleNameAttr();
1796 if (name != expectedName)
1797 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1800 auto elements = type.getElements();
1802 auto expectedNumElements = classOp.getNumPorts();
1804 return emitError() <<
"has wrong number of ports, got " <<
numElements
1805 <<
", expected " << expectedNumElements;
1807 auto portNames = classOp.getPortNames();
1808 auto portDirections = classOp.getPortDirections();
1809 auto portTypes = classOp.getPortTypes();
1812 auto element = elements[i];
1814 auto name = element.name;
1815 auto expectedName = portNames[i];
1816 if (name != expectedName)
1817 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
1818 <<
", expected " << expectedName;
1820 auto direction = element.direction;
1821 auto expectedDirection =
Direction(portDirections[i]);
1822 if (direction != expectedDirection)
1823 return emitError() <<
"port " << name <<
" has wrong direction, got "
1827 auto type = element.type;
1828 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
1829 if (type != expectedType)
1830 return emitError() <<
"port " << name <<
" has wrong type, got " << type
1831 <<
", expected " << expectedType;
1838 auto n = classOp.getNumPorts();
1839 SmallVector<ClassElement> elements;
1840 elements.reserve(n);
1841 for (
size_t i = 0; i < n; ++i)
1842 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
1843 classOp.getPortDirection(i)});
1844 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
1845 return ClassType::get(name, elements);
1848template <
typename OpTy>
1850 bool hasSSAIdentifiers) {
1851 auto *context = result.getContext();
1852 auto &builder = parser.getBuilder();
1853 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1857 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1860 StringAttr nameAttr;
1861 if (parser.parseSymbolName(nameAttr))
1863 properties.setSymName(nameAttr);
1866 SmallVector<OpAsmParser::Argument> entryArgs;
1867 SmallVector<Direction, 4> portDirections;
1868 SmallVector<Attribute, 4> portNames;
1869 SmallVector<Attribute, 4> portTypes;
1870 SmallVector<Attribute, 4> portAnnotations;
1871 SmallVector<Attribute, 4> portSyms;
1872 SmallVector<Attribute, 4> portLocs;
1874 false, entryArgs, portDirections,
1875 portNames, portTypes, portAnnotations, portSyms,
1880 for (
auto annos : portAnnotations)
1881 if (!cast<ArrayAttr>(annos).empty())
1885 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1888 assert(portNames.size() == portTypes.size());
1894 properties.setPortDirections(
1898 properties.setPortNames(builder.getArrayAttr(portNames));
1901 properties.setPortTypes(builder.getArrayAttr(portTypes));
1904 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1905 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1908 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1914 auto *bodyRegion = result.addRegion();
1916 if (hasSSAIdentifiers) {
1917 if (parser.parseRegion(*bodyRegion, entryArgs))
1919 if (bodyRegion->empty())
1920 bodyRegion->push_back(
new Block());
1930 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1931 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1932 p << visibility.getValue() <<
' ';
1935 p.printSymbolName(op.getName());
1939 Region ®ion = op->getRegion(0);
1940 Block *body =
nullptr;
1941 if (!region.empty())
1942 body = ®ion.front();
1945 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1946 {}, op.getPortSymbols(), op.getPortLocations());
1949 SmallVector<StringRef, 8> omittedAttrs = {
1950 "sym_name",
"portNames",
"portTypes",
"portDirections",
1951 "portSymbols",
"portLocations", visibilityAttrName};
1955 if (!needPortNamesAttr)
1956 omittedAttrs.push_back(
"portNames");
1958 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1961 if (!region.empty()) {
1963 auto printEntryBlockArgs =
false;
1964 auto printBlockTerminators =
false;
1965 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
1973void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
1974 ArrayRef<PortInfo> ports) {
1977 [](
const auto &port) {
return port.annotations.empty(); }) &&
1978 "class ports may not have annotations");
1980 buildClass<ClassOp>(builder, result, name, ports);
1983 auto *bodyRegion = result.regions[0].get();
1985 bodyRegion->push_back(body);
1988 for (
auto &elt : ports)
1989 body->addArgument(elt.type, elt.loc);
1992void ClassOp::build(::mlir::OpBuilder &odsBuilder,
1993 ::mlir::OperationState &odsState, Twine name,
1994 mlir::ArrayRef<mlir::StringRef> fieldNames,
1995 mlir::ArrayRef<mlir::Type> fieldTypes) {
1997 SmallVector<PortInfo, 10> ports;
1998 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
1999 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2001 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2004 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2006 auto &body = odsState.regions[0]->getBlocks().front();
2007 auto prevLoc = odsBuilder.saveInsertionPoint();
2008 odsBuilder.setInsertionPointToEnd(&body);
2009 auto args = body.getArguments();
2010 auto loc = odsState.location;
2011 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2012 odsBuilder.create<PropAssignOp>(loc, args[i + 1], args[i]);
2014 odsBuilder.restoreInsertionPoint(prevLoc);
2016void ClassOp::print(OpAsmPrinter &p) {
2020ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2021 auto hasSSAIdentifiers =
true;
2022 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2025LogicalResult ClassOp::verify() {
2027 auto type = operand.getType();
2028 if (!isa<PropertyType>(type)) {
2029 emitOpError(
"ports on a class must be properties");
2038ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2042void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2047SmallVector<PortInfo> ClassOp::getPorts() {
2048 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2051void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2052 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2056void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2057 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2060Convention ClassOp::getConvention() {
return Convention::Internal; }
2062ConventionAttr ClassOp::getConventionAttr() {
2063 return ConventionAttr::get(getContext(), getConvention());
2066ArrayAttr ClassOp::getParameters() {
return {}; }
2068ArrayAttr ClassOp::getPortAnnotationsAttr() {
2069 return ArrayAttr::get(getContext(), {});
2072ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2074void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2075 llvm_unreachable(
"classes do not support annotations");
2078ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2080ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2082SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2083 return ::getPortListImpl(*
this);
2087 return ::getPortImpl(*
this, idx);
2090BlockArgument ClassOp::getArgument(
size_t portNumber) {
2094bool ClassOp::canDiscardOnUseEmpty() {
2105void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2106 StringAttr name, ArrayRef<PortInfo> ports) {
2109 [](
const auto &port) {
return port.annotations.empty(); }) &&
2110 "class ports may not have annotations");
2111 buildClass<ClassOp>(builder, result, name, ports);
2114void ExtClassOp::print(OpAsmPrinter &p) {
2118ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2119 auto hasSSAIdentifiers =
false;
2120 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2124ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2128void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2133SmallVector<PortInfo> ExtClassOp::getPorts() {
2134 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2137void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2138 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2141void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2142 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2145Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2147ConventionAttr ExtClassOp::getConventionAttr() {
2148 return ConventionAttr::get(getContext(), getConvention());
2151ArrayAttr ExtClassOp::getLayersAttr() {
2152 return ArrayAttr::get(getContext(), {});
2155ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2157ArrayAttr ExtClassOp::getParameters() {
return {}; }
2159ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2160 return ArrayAttr::get(getContext(), {});
2163ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2165void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2166 llvm_unreachable(
"classes do not support annotations");
2169SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2170 return ::getPortListImpl(*
this);
2174 return ::getPortImpl(*
this, idx);
2177bool ExtClassOp::canDiscardOnUseEmpty() {
2188LogicalResult LayerOp::verify() {
2199 if (getConvention() == LayerConvention::Bind) {
2200 Operation *parentOp = (*this)->getParentOp();
2201 while (
auto parentLayer = dyn_cast<LayerOp>(parentOp)) {
2202 if (parentLayer.getConvention() == LayerConvention::Inline) {
2203 auto diag = emitOpError() <<
"has bind convention and cannot be nested "
2204 "under a layer with inline convention";
2205 diag.attachNote(parentLayer.getLoc())
2206 <<
"layer with inline convention here";
2209 parentOp = parentOp->getParentOp();
2220void InstanceOp::build(OpBuilder &builder, OperationState &result,
2221 TypeRange resultTypes, StringRef moduleName,
2222 StringRef name, NameKindEnum nameKind,
2223 ArrayRef<Direction> portDirections,
2224 ArrayRef<Attribute> portNames,
2225 ArrayRef<Attribute> annotations,
2226 ArrayRef<Attribute> portAnnotations,
2227 ArrayRef<Attribute> layers,
bool lowerToBind,
2228 bool doNotPrint, StringAttr innerSym) {
2229 build(builder, result, resultTypes, moduleName, name, nameKind,
2230 portDirections, portNames, annotations, portAnnotations, layers,
2231 lowerToBind, doNotPrint,
2232 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2235void InstanceOp::build(OpBuilder &builder, OperationState &result,
2236 TypeRange resultTypes, StringRef moduleName,
2237 StringRef name, NameKindEnum nameKind,
2238 ArrayRef<Direction> portDirections,
2239 ArrayRef<Attribute> portNames,
2240 ArrayRef<Attribute> annotations,
2241 ArrayRef<Attribute> portAnnotations,
2242 ArrayRef<Attribute> layers,
bool lowerToBind,
2243 bool doNotPrint, hw::InnerSymAttr innerSym) {
2244 result.addTypes(resultTypes);
2245 result.getOrAddProperties<Properties>().setModuleName(
2246 SymbolRefAttr::get(builder.getContext(), moduleName));
2247 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2248 result.getOrAddProperties<Properties>().setPortDirections(
2250 result.getOrAddProperties<Properties>().setPortNames(
2251 builder.getArrayAttr(portNames));
2252 result.getOrAddProperties<Properties>().setAnnotations(
2253 builder.getArrayAttr(annotations));
2254 result.getOrAddProperties<Properties>().setLayers(
2255 builder.getArrayAttr(layers));
2257 result.getOrAddProperties<Properties>().setLowerToBind(
2258 builder.getUnitAttr());
2260 result.getOrAddProperties<Properties>().setDoNotPrint(
2261 builder.getUnitAttr());
2263 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2265 result.getOrAddProperties<Properties>().setNameKind(
2266 NameKindEnumAttr::get(builder.getContext(), nameKind));
2268 if (portAnnotations.empty()) {
2269 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2270 builder.getArrayAttr({}));
2271 result.getOrAddProperties<Properties>().setPortAnnotations(
2272 builder.getArrayAttr(portAnnotationsVec));
2274 assert(portAnnotations.size() == resultTypes.size());
2275 result.getOrAddProperties<Properties>().setPortAnnotations(
2276 builder.getArrayAttr(portAnnotations));
2280void InstanceOp::build(OpBuilder &builder, OperationState &result,
2281 FModuleLike module, StringRef name,
2282 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2283 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2284 bool doNotPrint, hw::InnerSymAttr innerSym) {
2287 SmallVector<Type> resultTypes;
2288 resultTypes.reserve(module.getNumPorts());
2290 module.getPortTypes(), std::back_inserter(resultTypes),
2291 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2294 ArrayAttr portAnnotationsAttr;
2295 if (portAnnotations.empty()) {
2296 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2297 resultTypes.size(), builder.getArrayAttr({})));
2299 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2303 builder, result, resultTypes,
2304 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2305 builder.getStringAttr(name),
2306 NameKindEnumAttr::get(builder.getContext(), nameKind),
2307 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2308 builder.getArrayAttr(annotations), portAnnotationsAttr,
2309 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2310 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2313void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2314 ArrayRef<PortInfo> ports, StringRef moduleName,
2315 StringRef name, NameKindEnum nameKind,
2316 ArrayRef<Attribute> annotations,
2317 ArrayRef<Attribute> layers,
bool lowerToBind,
2318 bool doNotPrint, hw::InnerSymAttr innerSym) {
2320 SmallVector<Type> newResultTypes;
2321 SmallVector<Direction> newPortDirections;
2322 SmallVector<Attribute> newPortNames;
2323 SmallVector<Attribute> newPortAnnotations;
2324 for (
auto &p : ports) {
2325 newResultTypes.push_back(p.type);
2326 newPortDirections.push_back(p.direction);
2327 newPortNames.push_back(p.name);
2328 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2331 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2332 newPortDirections, newPortNames, annotations, newPortAnnotations,
2333 layers, lowerToBind, doNotPrint, innerSym);
2336LogicalResult InstanceOp::verify() {
2339 SmallVector<SymbolRefAttr> missingLayers;
2340 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2342 missingLayers.push_back(layer);
2344 if (missingLayers.empty())
2348 emitOpError(
"ambient layers are insufficient to instantiate module");
2349 auto ¬e = diag.attachNote();
2350 note <<
"missing layer requirements: ";
2351 interleaveComma(missingLayers, note);
2357InstanceOp InstanceOp::erasePorts(OpBuilder &builder,
2358 const llvm::BitVector &portIndices) {
2359 assert(portIndices.size() >= getNumResults() &&
2360 "portIndices is not at least as large as getNumResults()");
2362 if (portIndices.none())
2365 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2366 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2367 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2369 SmallVector<Attribute> newPortNames =
2371 SmallVector<Attribute> newPortAnnotations =
2374 auto newOp = builder.create<InstanceOp>(
2375 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2376 newPortDirections, newPortNames, getAnnotations().getValue(),
2377 newPortAnnotations, getLayers(), getLowerToBind(), getDoNotPrint(),
2380 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2381 oldIdx != numOldPorts; ++oldIdx) {
2382 if (portIndices.test(oldIdx)) {
2383 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2386 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2394 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2395 newOp->setAttr(
"output_file", outputFile);
2400ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2401 assert(portIdx < getNumResults() &&
2402 "index should be smaller than result number");
2403 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2406void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2407 assert(annotations.size() == getNumResults() &&
2408 "number of annotations is not equal to result number");
2409 (*this)->setAttr(
"portAnnotations",
2410 ArrayAttr::get(getContext(), annotations));
2414InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2415 auto portSize = ports.size();
2416 auto newPortCount = getNumResults() + portSize;
2417 SmallVector<Direction> newPortDirections;
2418 newPortDirections.reserve(newPortCount);
2419 SmallVector<Attribute> newPortNames;
2420 newPortNames.reserve(newPortCount);
2421 SmallVector<Type> newPortTypes;
2422 newPortTypes.reserve(newPortCount);
2423 SmallVector<Attribute> newPortAnnos;
2424 newPortAnnos.reserve(newPortCount);
2426 unsigned oldIndex = 0;
2427 unsigned newIndex = 0;
2428 while (oldIndex + newIndex < newPortCount) {
2430 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2431 auto &newPort = ports[newIndex].second;
2432 newPortDirections.push_back(newPort.direction);
2433 newPortNames.push_back(newPort.name);
2434 newPortTypes.push_back(newPort.type);
2435 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2439 newPortDirections.push_back(getPortDirection(oldIndex));
2440 newPortNames.push_back(getPortName(oldIndex));
2441 newPortTypes.push_back(getType(oldIndex));
2442 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2448 return OpBuilder(*this).create<InstanceOp>(
2449 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2450 newPortDirections, newPortNames, getAnnotations().getValue(),
2451 newPortAnnos, getLayers(), getLowerToBind(), getDoNotPrint(),
2455LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2457 getModuleNameAttr());
2460StringRef InstanceOp::getInstanceName() {
return getName(); }
2462StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2464void InstanceOp::print(OpAsmPrinter &p) {
2467 p.printKeywordOrString(
getName());
2468 if (
auto attr = getInnerSymAttr()) {
2470 p.printSymbolName(attr.getSymName());
2472 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2473 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2476 SmallVector<StringRef, 10> omittedAttrs = {
2477 "moduleName",
"name",
"portDirections",
2478 "portNames",
"portTypes",
"portAnnotations",
2479 "inner_sym",
"nameKind"};
2480 if (getAnnotations().
empty())
2481 omittedAttrs.push_back(
"annotations");
2482 if (getLayers().
empty())
2483 omittedAttrs.push_back(
"layers");
2484 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2488 p.printSymbolName(getModuleName());
2491 SmallVector<Attribute> portTypes;
2492 portTypes.reserve(getNumResults());
2493 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2496 getPortNames().getValue(), portTypes,
2497 getPortAnnotations().getValue(), {}, {});
2500ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2501 auto *context = parser.getContext();
2502 auto &properties = result.getOrAddProperties<Properties>();
2505 hw::InnerSymAttr innerSymAttr;
2506 FlatSymbolRefAttr moduleName;
2507 SmallVector<OpAsmParser::Argument> entryArgs;
2508 SmallVector<Direction, 4> portDirections;
2509 SmallVector<Attribute, 4> portNames;
2510 SmallVector<Attribute, 4> portTypes;
2511 SmallVector<Attribute, 4> portAnnotations;
2512 SmallVector<Attribute, 4> portSyms;
2513 SmallVector<Attribute, 4> portLocs;
2514 NameKindEnumAttr nameKind;
2516 if (parser.parseKeywordOrString(&name))
2518 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2519 if (parser.parseCustomAttributeWithFallback(
2520 innerSymAttr, ::mlir::Type{},
2522 result.attributes)) {
2523 return ::mlir::failure();
2527 parser.parseOptionalAttrDict(result.attributes) ||
2528 parser.parseAttribute(moduleName) ||
2530 false, entryArgs, portDirections,
2531 portNames, portTypes, portAnnotations, portSyms,
2538 properties.setModuleName(moduleName);
2539 properties.setName(StringAttr::get(context, name));
2540 properties.setNameKind(nameKind);
2541 properties.setPortDirections(
2543 properties.setPortNames(ArrayAttr::get(context, portNames));
2544 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2548 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2549 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2552 result.types.reserve(portTypes.size());
2554 portTypes, std::back_inserter(result.types),
2555 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2560void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2565 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2566 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2570std::optional<size_t> InstanceOp::getTargetResultIndex() {
2572 return std::nullopt;
2579void InstanceChoiceOp::build(
2580 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2581 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2582 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2583 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2585 SmallVector<Type> resultTypes;
2586 for (Attribute portType : defaultModule.getPortTypes())
2587 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2590 ArrayAttr portAnnotationsAttr;
2591 if (portAnnotations.empty()) {
2592 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2593 resultTypes.size(), builder.getArrayAttr({})));
2595 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2599 SmallVector<Attribute> moduleNames, caseNames;
2600 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2601 for (
auto [caseOption, caseModule] : cases) {
2602 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2603 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2604 {SymbolRefAttr::get(caseOption)}));
2605 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2608 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2609 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2610 NameKindEnumAttr::get(builder.getContext(), nameKind),
2611 defaultModule.getPortDirectionsAttr(),
2612 defaultModule.getPortNamesAttr(),
2613 builder.getArrayAttr(annotations), portAnnotationsAttr,
2614 defaultModule.getLayersAttr(),
2615 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2618std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2619 return std::nullopt;
2622void InstanceChoiceOp::print(OpAsmPrinter &p) {
2625 p.printKeywordOrString(
getName());
2626 if (
auto attr = getInnerSymAttr()) {
2628 p.printSymbolName(attr.getSymName());
2630 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2631 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2634 SmallVector<StringRef, 10> omittedAttrs = {
2635 "moduleNames",
"caseNames",
"name",
2636 "portDirections",
"portNames",
"portTypes",
2637 "portAnnotations",
"inner_sym",
"nameKind"};
2638 if (getAnnotations().
empty())
2639 omittedAttrs.push_back(
"annotations");
2640 if (getLayers().
empty())
2641 omittedAttrs.push_back(
"layers");
2642 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2647 auto moduleNames = getModuleNamesAttr();
2648 auto caseNames = getCaseNamesAttr();
2650 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2652 p <<
" alternatives ";
2654 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2656 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2660 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2661 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2663 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2669 SmallVector<Attribute> portTypes;
2670 portTypes.reserve(getNumResults());
2671 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2674 getPortNames().getValue(), portTypes,
2675 getPortAnnotations().getValue(), {}, {});
2678ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2679 OperationState &result) {
2680 auto *context = parser.getContext();
2681 auto &properties = result.getOrAddProperties<Properties>();
2684 hw::InnerSymAttr innerSymAttr;
2685 SmallVector<Attribute> moduleNames;
2686 SmallVector<Attribute> caseNames;
2687 SmallVector<OpAsmParser::Argument> entryArgs;
2688 SmallVector<Direction, 4> portDirections;
2689 SmallVector<Attribute, 4> portNames;
2690 SmallVector<Attribute, 4> portTypes;
2691 SmallVector<Attribute, 4> portAnnotations;
2692 SmallVector<Attribute, 4> portSyms;
2693 SmallVector<Attribute, 4> portLocs;
2694 NameKindEnumAttr nameKind;
2696 if (parser.parseKeywordOrString(&name))
2698 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2699 if (parser.parseCustomAttributeWithFallback(
2700 innerSymAttr, Type{},
2702 result.attributes)) {
2707 parser.parseOptionalAttrDict(result.attributes))
2710 FlatSymbolRefAttr defaultModuleName;
2711 if (parser.parseAttribute(defaultModuleName))
2713 moduleNames.push_back(defaultModuleName);
2717 FlatSymbolRefAttr optionName;
2718 if (parser.parseKeyword(
"alternatives") ||
2719 parser.parseAttribute(optionName) || parser.parseLBrace())
2722 FlatSymbolRefAttr moduleName;
2723 StringAttr caseName;
2724 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2725 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2727 moduleNames.push_back(moduleName);
2728 caseNames.push_back(SymbolRefAttr::get(
2729 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2730 if (failed(parser.parseOptionalComma()))
2733 if (parser.parseRBrace())
2738 false, entryArgs, portDirections,
2739 portNames, portTypes, portAnnotations, portSyms,
2745 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
2746 properties.setCaseNames(ArrayAttr::get(context, caseNames));
2747 properties.setName(StringAttr::get(context, name));
2748 properties.setNameKind(nameKind);
2749 properties.setPortDirections(
2751 properties.setPortNames(ArrayAttr::get(context, portNames));
2752 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2756 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2757 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2760 result.types.reserve(portTypes.size());
2762 portTypes, std::back_inserter(result.types),
2763 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2768void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2770 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
2771 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
2774LogicalResult InstanceChoiceOp::verify() {
2775 if (getCaseNamesAttr().
empty())
2776 return emitOpError() <<
"must have at least one case";
2777 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2778 return emitOpError() <<
"number of referenced modules does not match the "
2779 "number of options";
2784 SmallVector<SymbolRefAttr> missingLayers;
2785 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2787 missingLayers.push_back(layer);
2789 if (missingLayers.empty())
2793 emitOpError(
"ambient layers are insufficient to instantiate module");
2794 auto ¬e = diag.attachNote();
2795 note <<
"missing layer requirements: ";
2796 interleaveComma(missingLayers, note);
2801InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2802 auto caseNames = getCaseNamesAttr();
2803 for (
auto moduleName : getModuleNamesAttr()) {
2805 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
2809 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
2810 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2811 auto ref = cast<SymbolRefAttr>(caseNames[i]);
2812 auto refRoot = ref.getRootReference();
2813 if (ref.getRootReference() != root)
2814 return emitOpError() <<
"case " << ref
2815 <<
" is not in the same option group as "
2818 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2819 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2821 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2822 return emitOpError() <<
"option " << refRoot
2823 <<
" does not contain option case " << ref;
2830InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2831 auto caseNames = getCaseNamesAttr();
2832 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2833 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
2834 if (caseSym == option.getSymName())
2835 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
2837 return getDefaultTargetAttr();
2840SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2841InstanceChoiceOp::getTargetChoices() {
2842 auto caseNames = getCaseNamesAttr();
2843 auto moduleNames = getModuleNamesAttr();
2844 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2845 for (
size_t i = 0; i < caseNames.size(); ++i) {
2846 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
2847 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
2854InstanceChoiceOp::erasePorts(OpBuilder &builder,
2855 const llvm::BitVector &portIndices) {
2856 assert(portIndices.size() >= getNumResults() &&
2857 "portIndices is not at least as large as getNumResults()");
2859 if (portIndices.none())
2862 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2863 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2864 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2866 SmallVector<Attribute> newPortNames =
2868 SmallVector<Attribute> newPortAnnotations =
2871 auto newOp = builder.create<InstanceChoiceOp>(
2872 getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
getName(),
2874 ArrayAttr::get(getContext(), newPortNames), getAnnotationsAttr(),
2875 ArrayAttr::get(getContext(), newPortAnnotations), getLayers(),
2878 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2879 oldIdx != numOldPorts; ++oldIdx) {
2880 if (portIndices.test(oldIdx)) {
2881 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2884 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2892 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2893 newOp->setAttr(
"output_file", outputFile);
2902ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2903 assert(portIdx < getNumResults() &&
2904 "index should be smaller than result number");
2905 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2908void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2909 assert(annotations.size() == getNumResults() &&
2910 "number of annotations is not equal to result number");
2911 (*this)->setAttr(
"portAnnotations",
2912 ArrayAttr::get(getContext(), annotations));
2916void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
2917 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2920 numReadWritePorts = 0;
2922 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2923 auto portKind = getPortKind(i);
2924 if (portKind == MemOp::PortKind::Debug)
2926 else if (portKind == MemOp::PortKind::Read)
2928 else if (portKind == MemOp::PortKind::Write) {
2931 ++numReadWritePorts;
2936LogicalResult MemOp::verify() {
2940 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2946 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2947 auto portName = getPortName(i);
2952 BundleType portBundleType =
2953 type_dyn_cast<BundleType>(getResult(i).getType());
2956 if (!portNamesSet.insert(portName).second) {
2957 emitOpError() <<
"has non-unique port name " << portName;
2965 auto elt = getPortNamed(portName);
2967 emitOpError() <<
"could not get port with name " << portName;
2970 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2973 if (portKind == MemOp::PortKind::Debug &&
2974 !type_isa<RefType>(getResult(i).getType()))
2975 return emitOpError() <<
"has an invalid type on port " << portName
2976 <<
" (expected Read/Write/ReadWrite/Debug)";
2977 if (type_isa<RefType>(firrtlType) && e == 1)
2978 return emitOpError()
2979 <<
"cannot have only one port of debug type. Debug port can only "
2980 "exist alongside other read/write/read-write port";
2985 if (portKind == MemOp::PortKind::Debug) {
2986 auto resType = type_cast<RefType>(getResult(i).getType());
2987 if (!(resType && type_isa<FVectorType>(resType.getType())))
2988 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2989 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2991 auto dataTypeOption = portBundleType.getElement(
"data");
2992 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2993 dataTypeOption = portBundleType.getElement(
"wdata");
2994 if (!dataTypeOption) {
2995 emitOpError() <<
"has no data field on port " << portName
2996 <<
" (expected to see \"data\" for a read or write "
2997 "port or \"rdata\" for a read/write port)";
3000 dataType = dataTypeOption->type;
3002 if (portKind == MemOp::PortKind::Read) {
3009 emitOpError() <<
"has non-passive data type on port " << portName
3010 <<
" (memory types must be passive)";
3015 if (dataType.containsAnalog()) {
3016 emitOpError() <<
"has a data type that contains an analog type on port "
3018 <<
" (memory types cannot contain analog types)";
3026 getTypeForPort(getDepth(), dataType, portKind,
3027 dataType.isGround() ? getMaskBits() : 0);
3030 auto originalType = getResult(i).getType();
3031 if (originalType != expectedType) {
3032 StringRef portKindName;
3034 case MemOp::PortKind::Read:
3035 portKindName =
"read";
3037 case MemOp::PortKind::Write:
3038 portKindName =
"write";
3040 case MemOp::PortKind::ReadWrite:
3041 portKindName =
"readwrite";
3043 case MemOp::PortKind::Debug:
3044 portKindName =
"dbg";
3047 emitOpError() <<
"has an invalid type for port " << portName
3048 <<
" of determined kind \"" << portKindName
3049 <<
"\" (expected " << expectedType <<
", but got "
3050 << originalType <<
")";
3056 if (oldDataType && oldDataType != dataType) {
3057 emitOpError() <<
"port " << getPortName(i)
3058 <<
" has a different type than port " << getPortName(i - 1)
3059 <<
" (expected " << oldDataType <<
", but got " << dataType
3064 oldDataType = dataType;
3067 auto maskWidth = getMaskBits();
3069 auto dataWidth = getDataType().getBitWidthOrSentinel();
3070 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3071 return emitOpError(
"the mask width cannot be greater than "
3074 if (getPortAnnotations().size() != getNumResults())
3075 return emitOpError(
"the number of result annotations should be "
3076 "equal to the number of results");
3082 return std::max(1U, llvm::Log2_64_Ceil(depth));
3088 PortKind portKind,
size_t maskBits) {
3090 auto *context = dataType.getContext();
3091 if (portKind == PortKind::Debug)
3092 return RefType::get(FVectorType::get(dataType, depth));
3098 maskType = UIntType::get(context, maskBits);
3100 auto getId = [&](StringRef name) -> StringAttr {
3101 return StringAttr::get(context, name);
3104 SmallVector<BundleType::BundleElement, 7> portFields;
3108 portFields.push_back({getId(
"addr"),
false, addressType});
3109 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3110 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3113 case PortKind::Read:
3114 portFields.push_back({getId(
"data"),
true, dataType});
3117 case PortKind::Write:
3118 portFields.push_back({getId(
"data"),
false, dataType});
3119 portFields.push_back({getId(
"mask"),
false, maskType});
3122 case PortKind::ReadWrite:
3123 portFields.push_back({getId(
"rdata"),
true, dataType});
3124 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3125 portFields.push_back({getId(
"wdata"),
false, dataType});
3126 portFields.push_back({getId(
"wmask"),
false, maskType});
3129 llvm::report_fatal_error(
"memory port kind not handled");
3133 return BundleType::get(context, portFields);
3137SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3138 SmallVector<MemOp::NamedPort> result;
3140 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3142 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3149MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3151 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3155MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3157 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3161size_t MemOp::getMaskBits() {
3163 for (
auto res : getResults()) {
3164 if (type_isa<RefType>(res.getType()))
3166 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3173 if (t.name.getValue().contains(
"mask"))
3176 if (type_isa<UIntType>(mType))
3186 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3188 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3189 return type_cast<FVectorType>(refType.getType()).getElementType();
3190 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3192 StringRef dataFieldName =
"data";
3194 dataFieldName =
"rdata";
3196 return type_cast<BundleType>(firstPortType.getPassiveType())
3197 .getElementType(dataFieldName);
3200StringAttr MemOp::getPortName(
size_t resultNo) {
3201 return cast<StringAttr>(getPortNames()[resultNo]);
3205 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3208Value MemOp::getPortNamed(StringAttr name) {
3209 auto namesArray = getPortNames();
3210 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3211 if (namesArray[i] == name) {
3212 assert(i < getNumResults() &&
" names array out of sync with results");
3213 return getResult(i);
3222 size_t numReadPorts = 0;
3223 size_t numWritePorts = 0;
3224 size_t numReadWritePorts = 0;
3226 SmallVector<int32_t> writeClockIDs;
3228 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3229 auto portKind = op.getPortKind(i);
3230 if (portKind == MemOp::PortKind::Read)
3232 else if (portKind == MemOp::PortKind::Write) {
3233 for (
auto *a : op.getResult(i).getUsers()) {
3234 auto subfield = dyn_cast<SubfieldOp>(a);
3235 if (!subfield || subfield.getFieldIndex() != 2)
3237 auto clockPort = a->getResult(0);
3238 for (
auto *b : clockPort.getUsers()) {
3239 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3240 if (
connect.getDest() == clockPort) {
3243 connect.getSrc(),
true,
true,
true),
3245 if (result.second) {
3246 writeClockIDs.push_back(numWritePorts);
3248 writeClockIDs.push_back(result.first->second);
3257 ++numReadWritePorts;
3264 op.emitError(
"'firrtl.mem' should have simple type and known width");
3265 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3267 if (op->hasAttr(
"modName"))
3268 modName = op->getAttrOfType<StringAttr>(
"modName");
3270 SmallString<8> clocks;
3271 for (
auto a : writeClockIDs)
3272 clocks.
append(Twine((char)(a +
'a')).str());
3273 SmallString<32> initStr;
3278 for (
auto c : init.getFilename().getValue())
3279 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3280 (c >=
'0' && c <=
'9'))
3281 initStr.push_back(c);
3282 initStr.push_back(
'_');
3283 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3284 initStr.push_back(
'_');
3285 initStr.push_back(init.getIsInline() ?
't' :
'f');
3287 modName = StringAttr::get(
3290 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3291 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3292 numReadWritePorts, (
size_t)width, op.getDepth(),
3293 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3294 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3295 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3297 return {numReadPorts,
3302 op.getReadLatency(),
3303 op.getWriteLatency(),
3305 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3306 seq::WUW::PortOrder,
3309 op.getMaskBits() > 1,
3315void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3320 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3321 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3325std::optional<size_t> MemOp::getTargetResultIndex() {
3327 return std::nullopt;
3335 OpAsmSetValueNameFn setNameFn) {
3338 setNameFn(op.getDataRaw(), name);
3339 if (op.isForceable())
3340 setNameFn(op.getDataRef(), (name +
"_ref").str());
3343void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3347LogicalResult NodeOp::inferReturnTypes(
3348 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3349 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3350 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3351 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3352 if (operands.empty())
3354 Adaptor adaptor(operands, attributes, properties, regions);
3355 inferredReturnTypes.push_back(adaptor.getInput().getType());
3356 if (adaptor.getForceable()) {
3358 true, adaptor.getInput().getType());
3359 if (!forceableType) {
3361 ::mlir::emitError(*location,
"cannot force a node of type ")
3362 << operands[0].getType();
3365 inferredReturnTypes.push_back(forceableType);
3370std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3372void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3376std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3378SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3379RegOp::computeDataFlow() {
3384LogicalResult RegResetOp::verify() {
3385 auto reset = getResetValue();
3392 return emitError(
"type mismatch between register ")
3393 << regType <<
" and reset value " << resetType;
3398std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3400void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3409FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3410 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3412 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3414 if (!isa<FModuleLike>(op)) {
3415 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3416 <<
" is not a module";
3417 d.attachNote(op->getLoc()) <<
"target defined here";
3429SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3430 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3432 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3434 auto complain = [&] {
3435 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3436 d.attachNote(op->getLoc()) <<
"target defined here";
3440 auto module = dyn_cast<FModuleLike>(op);
3442 return complain() <<
"is not a module";
3444 auto numPorts =
module.getPortDirections().size();
3446 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3448 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3449 llvm::function_ref<bool(Type)> checkType,
3450 StringRef expType) {
3451 auto name =
module.getPortNameAttr(idx);
3452 if (name != expName) {
3453 complain() <<
"port " << idx <<
" must be called \"" << expName
3454 <<
"\", got " << name <<
" instead";
3457 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3461 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3462 <<
", got " << stringify(dir) <<
" instead";
3465 if (
auto type = module.getPortType(idx); !checkType(type)) {
3466 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3467 <<
"', got " << type <<
" instead";
3473 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3474 auto isBool = [](Type type) {
3475 if (
auto uintType = dyn_cast<UIntType>(type))
3476 return uintType.getWidth() == 1;
3479 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3489void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3493SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3494RegResetOp::computeDataFlow() {
3499std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3501LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3502 auto refType = type_dyn_cast<RefType>(getType(0));
3507 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3508 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3515LogicalResult ContractOp::verify() {
3516 if (getBody().getArgumentTypes() != getInputs().getType())
3517 return emitOpError(
"result types and region argument types must match");
3525void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3527 build(builder, state, klass.getInstanceType(),
3528 StringAttr::get(builder.getContext(), name));
3531LogicalResult ObjectOp::verify() {
return success(); }
3533LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3534 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3535 auto classType = getType();
3536 auto className = classType.getNameAttr();
3539 auto classOp = dyn_cast_or_null<ClassLike>(
3540 symbolTable.lookupSymbolIn(circuitOp, className));
3542 return emitOpError() <<
"references unknown class " << className;
3545 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3551StringAttr ObjectOp::getClassNameAttr() {
3552 return getType().getNameAttr().getAttr();
3555StringRef ObjectOp::getClassName() {
return getType().getName(); }
3557ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3558 auto symRef = getType().getNameAttr();
3559 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3562Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3563 return getReferencedClass(symtbl);
3566StringRef ObjectOp::getInstanceName() {
return getName(); }
3568StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3570StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3572StringAttr ObjectOp::getReferencedModuleNameAttr() {
3573 return getClassNameAttr();
3576void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3577 setNameFn(getResult(),
getName());
3584LogicalResult AttachOp::verify() {
3586 std::optional<int32_t> commonWidth;
3587 for (
auto operand : getOperands()) {
3588 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3592 commonWidth = thisWidth;
3595 if (commonWidth != thisWidth)
3596 return emitOpError(
"is inavlid as not all known operand widths match");
3603 Value dst = connect->getOperand(0);
3604 Value src = connect->getOperand(1);
3613 if (isa<PropertyType>(src.getType()) ||
3617 auto diag = emitError(connect->getLoc());
3618 diag <<
"connect has invalid flow: the source expression ";
3620 diag <<
"\"" << srcName <<
"\" ";
3621 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3622 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3630 auto diag = emitError(connect->getLoc());
3631 diag <<
"connect has invalid flow: the destination expression ";
3633 diag <<
"\"" << dstName <<
"\" ";
3634 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3635 return diag.attachNote(dstRef.getLoc())
3636 <<
"the destination was defined here";
3645 bool outerTypeIsConst =
false) {
3646 auto typeIsConst = outerTypeIsConst || type.
isConst();
3651 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3652 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3653 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3657 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3669 auto dest = connect.getDest();
3670 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3671 auto src = connect.getSrc();
3672 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3673 if (!destType || !srcType)
3676 auto destRefinedType = destType;
3677 auto srcRefinedType = srcType;
3682 auto findFieldDeclarationRefiningFieldType =
3684 while (
auto *definingOp = value.getDefiningOp()) {
3685 bool shouldContinue =
true;
3686 TypeSwitch<Operation *>(definingOp)
3687 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3688 .Case<SubaccessOp>([&](SubaccessOp op) {
3692 .getElementTypePreservingConst()
3694 originalFieldType = originalFieldType.getConstType(
true);
3695 value = op.getInput();
3697 .Default([&](Operation *) { shouldContinue =
false; });
3698 if (!shouldContinue)
3704 auto destDeclaration =
3705 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3706 auto srcDeclaration =
3707 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3709 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3710 Value declaration) -> LogicalResult {
3711 auto *declarationBlock = declaration.getParentBlock();
3712 auto *block = connect->getBlock();
3713 while (block && block != declarationBlock) {
3714 auto *parentOp = block->getParentOp();
3716 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3717 whenOp && !whenOp.getCondition().getType().isConst()) {
3719 return connect.emitOpError()
3720 <<
"assignment to 'const' type " << type
3721 <<
" is dependent on a non-'const' condition";
3722 return connect->emitOpError()
3723 <<
"assignment to nested 'const' member of type " << type
3724 <<
" is dependent on a non-'const' condition";
3727 block = parentOp->getBlock();
3732 auto emitSubaccessError = [&] {
3733 return connect.emitError(
3734 "assignment to non-'const' subaccess of 'const' type is disallowed");
3740 if (destType != destRefinedType)
3741 return emitSubaccessError();
3743 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3748 if (srcRefinedType.containsConst() &&
3751 if (srcType != srcRefinedType)
3752 return emitSubaccessError();
3753 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3760LogicalResult ConnectOp::verify() {
3761 auto dstType = getDest().getType();
3762 auto srcType = getSrc().getType();
3763 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3764 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3765 if (!dstBaseType || !srcBaseType) {
3766 if (dstType != srcType)
3767 return emitError(
"may not connect different non-base types");
3770 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3771 return emitError(
"analog types may not be connected");
3775 return emitError(
"type mismatch between destination ")
3776 << dstBaseType <<
" and source " << srcBaseType;
3781 return emitError(
"destination ")
3782 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3795LogicalResult MatchingConnectOp::verify() {
3796 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3797 auto baseType = type_cast<FIRRTLBaseType>(type);
3800 if (baseType && baseType.containsAnalog())
3801 return emitError(
"analog types may not be connected");
3806 "`SameAnonTypeOperands` trait should have already rejected "
3807 "structurally non-equivalent types");
3820LogicalResult RefDefineOp::verify() {
3830 for (
auto *user : getDest().getUsers()) {
3831 if (
auto conn = dyn_cast<FConnectLike>(user);
3832 conn && conn.getDest() == getDest() && conn != *
this)
3833 return emitError(
"destination reference cannot be reused by multiple "
3834 "operations, it can only capture a unique dataflow");
3838 if (
auto *op = getDest().getDefiningOp()) {
3840 if (isa<RefSubOp>(op))
3842 "destination reference cannot be a sub-element of a reference");
3843 if (isa<RefCastOp>(op))
3845 "destination reference cannot be a cast of another reference");
3853 SmallVector<SymbolRefAttr> missingLayers;
3855 auto diag = emitOpError(
"has more layer requirements than destination");
3856 auto ¬e = diag.attachNote();
3857 note <<
"additional layers required: ";
3858 interleaveComma(missingLayers, note);
3865LogicalResult PropAssignOp::verify() {
3871 for (
auto *user : getDest().getUsers()) {
3872 if (
auto conn = dyn_cast<FConnectLike>(user);
3873 conn && conn.getDest() == getDest() && conn != *
this)
3874 return emitError(
"destination property cannot be reused by multiple "
3875 "operations, it can only capture a unique dataflow");
3881void WhenOp::createElseRegion() {
3882 assert(!hasElseRegion() &&
"already has an else region");
3883 getElseRegion().push_back(
new Block());
3886void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
3887 bool withElseRegion, std::function<
void()> thenCtor,
3888 std::function<
void()> elseCtor) {
3889 OpBuilder::InsertionGuard guard(builder);
3890 result.addOperands(condition);
3893 builder.createBlock(result.addRegion());
3898 Region *elseRegion = result.addRegion();
3899 if (withElseRegion) {
3900 builder.createBlock(elseRegion);
3910LogicalResult MatchOp::verify() {
3911 FEnumType type = getInput().getType();
3914 auto numCases = getTags().size();
3915 auto numRegions = getNumRegions();
3916 if (numRegions != numCases)
3917 return emitOpError(
"expected ")
3918 << numRegions <<
" tags but got " << numCases;
3920 auto numTags = type.getNumElements();
3922 SmallDenseSet<int64_t> seen;
3923 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
3924 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3927 if (region.getNumArguments() != 1)
3928 return emitOpError(
"region should have exactly one argument");
3931 if (tagIndex >= numTags)
3932 return emitOpError(
"the tag index ")
3933 << tagIndex <<
" is out of the range of valid tags in " << type;
3936 auto [it, inserted] = seen.insert(tagIndex);
3938 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3939 <<
" is matched more than once";
3942 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3943 auto regionType = region.getArgument(0).getType();
3944 if (regionType != expectedType)
3945 return emitOpError(
"region type ")
3946 << regionType <<
" does not match the expected type "
3951 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3952 if (!seen.contains(i))
3953 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3958void MatchOp::print(OpAsmPrinter &p) {
3959 auto input = getInput();
3960 FEnumType type = input.getType();
3961 auto regions = getRegions();
3962 p <<
" " << input <<
" : " << type;
3963 SmallVector<StringRef> elided = {
"tags"};
3964 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3967 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
3970 p.printKeywordOrString(
3971 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3973 p.printRegionArgument(region.front().getArgument(0), {},
3976 p.printRegion(region,
false);
3983ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3984 auto *context = parser.getContext();
3985 auto &properties = result.getOrAddProperties<Properties>();
3986 OpAsmParser::UnresolvedOperand input;
3987 if (parser.parseOperand(input) || parser.parseColon())
3990 auto loc = parser.getCurrentLocation();
3992 if (parser.parseType(type))
3994 auto enumType = type_dyn_cast<FEnumType>(type);
3996 return parser.emitError(loc,
"expected enumeration type but got") << type;
3998 if (parser.resolveOperand(input, type, result.operands) ||
3999 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4000 parser.parseLBrace())
4003 auto i32Type = IntegerType::get(context, 32);
4004 SmallVector<Attribute> tags;
4007 if (failed(parser.parseOptionalKeyword(
"case")))
4011 auto nameLoc = parser.getCurrentLocation();
4013 OpAsmParser::Argument arg;
4014 auto *region = result.addRegion();
4015 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4016 parser.parseArgument(arg) || parser.parseRParen())
4020 auto index = enumType.getElementIndex(name);
4022 return parser.emitError(nameLoc,
"the tag \"")
4023 << name <<
"\" is not a member of the enumeration " << enumType;
4024 tags.push_back(IntegerAttr::get(i32Type, *index));
4027 arg.type = enumType.getElementTypePreservingConst(*index);
4028 if (parser.parseRegion(*region, arg))
4031 properties.setTags(ArrayAttr::get(context, tags));
4033 return parser.parseRBrace();
4036void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4038 MutableArrayRef<std::unique_ptr<Region>> regions) {
4039 auto &properties = result.getOrAddProperties<Properties>();
4040 result.addOperands(input);
4041 properties.setTags(tags);
4042 result.addRegions(regions);
4051 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4052 bool visitInvalidExpr(Operation *op) {
return false; }
4053 bool visitUnhandledExpr(Operation *op) {
return true; }
4059void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4062 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4063 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4064 auto width = ty.getWidthOrSentinel();
4068 name = (Twine(base) + Twine(width)).str();
4069 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4070 auto width = ty.getWidthOrSentinel();
4072 name =
"invalid_analog";
4074 name = (
"invalid_analog" + Twine(width)).str();
4075 }
else if (type_isa<AsyncResetType>(getType()))
4076 name =
"invalid_asyncreset";
4077 else if (type_isa<ResetType>(getType()))
4078 name =
"invalid_reset";
4079 else if (type_isa<ClockType>(getType()))
4080 name =
"invalid_clock";
4084 setNameFn(getResult(), name);
4087void ConstantOp::print(OpAsmPrinter &p) {
4089 p.printAttributeWithoutType(getValueAttr());
4091 p.printType(getType());
4092 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4095ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4096 auto &properties = result.getOrAddProperties<Properties>();
4099 auto loc = parser.getCurrentLocation();
4100 auto valueResult = parser.parseOptionalInteger(value);
4101 if (!valueResult.has_value())
4102 return parser.emitError(loc,
"expected integer value");
4106 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4107 parser.parseOptionalAttrDict(result.attributes))
4109 result.addTypes(resultType);
4115 if (width > value.getBitWidth()) {
4119 value = value.sext(width);
4120 }
else if (width < value.getBitWidth()) {
4123 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4124 : value.getActiveBits();
4125 if (width < neededBits)
4126 return parser.emitError(loc,
"constant out of range for result type ")
4128 value = value.trunc(width);
4132 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4134 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4135 properties.setValue(valueAttr);
4139LogicalResult ConstantOp::verify() {
4143 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4145 "firrtl.constant attribute bitwidth doesn't match return type");
4148 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4149 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4150 return emitError(
"firrtl.constant attribute has wrong sign");
4157void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4158 const APInt &value) {
4161 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4162 "incorrect attribute bitwidth for firrtl.constant");
4165 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4166 return build(builder, result, type, attr);
4171void ConstantOp::build(OpBuilder &builder, OperationState &result,
4172 const APSInt &value) {
4173 auto attr = IntegerAttr::get(builder.getContext(), value);
4175 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4176 return build(builder, result, type, attr);
4179void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4186 SmallString<32> specialNameBuffer;
4187 llvm::raw_svector_ostream specialName(specialNameBuffer);
4189 getValue().print(specialName, intTy.
isSigned());
4191 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4194 specialName << width;
4195 setNameFn(getResult(), specialName.str());
4198void SpecialConstantOp::print(OpAsmPrinter &p) {
4201 p << static_cast<unsigned>(getValue());
4203 p.printType(getType());
4204 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4207ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4208 OperationState &result) {
4209 auto &properties = result.getOrAddProperties<Properties>();
4213 auto loc = parser.getCurrentLocation();
4214 auto valueResult = parser.parseOptionalInteger(value);
4215 if (!valueResult.has_value())
4216 return parser.emitError(loc,
"expected integer value");
4219 if (value != 0 && value != 1)
4220 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4224 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4225 parser.parseOptionalAttrDict(result.attributes))
4227 result.addTypes(resultType);
4230 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4231 properties.setValue(valueAttr);
4235void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4236 SmallString<32> specialNameBuffer;
4237 llvm::raw_svector_ostream specialName(specialNameBuffer);
4239 specialName << static_cast<unsigned>(getValue());
4240 auto type = getType();
4241 if (type_isa<ClockType>(type)) {
4242 specialName <<
"_clock";
4243 }
else if (type_isa<ResetType>(type)) {
4244 specialName <<
"_reset";
4245 }
else if (type_isa<AsyncResetType>(type)) {
4246 specialName <<
"_asyncreset";
4248 setNameFn(getResult(), specialName.str());
4255 if (type.isGround()) {
4256 if (!isa<IntegerAttr>(attr)) {
4257 op->emitOpError(
"Ground type is not an integer attribute");
4262 auto attrlist = dyn_cast<ArrayAttr>(attr);
4264 op->emitOpError(
"expected array attribute for aggregate constant");
4267 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4268 if (array.getNumElements() != attrlist.size()) {
4269 op->emitOpError(
"array attribute (")
4270 << attrlist.size() <<
") has wrong size for vector constant ("
4271 << array.getNumElements() <<
")";
4274 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4278 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4279 if (bundle.getNumElements() != attrlist.size()) {
4280 op->emitOpError(
"array attribute (")
4281 << attrlist.size() <<
") has wrong size for bundle constant ("
4282 << bundle.getNumElements() <<
")";
4285 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4286 if (bundle.getElement(i).isFlip) {
4287 op->emitOpError(
"Cannot have constant bundle type with flip");
4295 op->emitOpError(
"Unknown aggregate type");
4299LogicalResult AggregateConstantOp::verify() {
4305Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4307 Attribute value = getFields();
4308 while (fieldID != 0) {
4309 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4310 auto index = bundle.getIndexForFieldID(fieldID);
4311 fieldID -= bundle.getFieldID(index);
4312 type = bundle.getElementType(index);
4313 value = cast<ArrayAttr>(value)[index];
4315 auto vector = type_cast<FVectorType>(type);
4316 auto index = vector.getIndexForFieldID(fieldID);
4317 fieldID -= vector.getFieldID(index);
4318 type = vector.getElementType();
4319 value = cast<ArrayAttr>(value)[index];
4325void FIntegerConstantOp::print(OpAsmPrinter &p) {
4327 p.printAttributeWithoutType(getValueAttr());
4328 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4331ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4332 OperationState &result) {
4333 auto *context = parser.getContext();
4334 auto &properties = result.getOrAddProperties<Properties>();
4336 if (parser.parseInteger(value) ||
4337 parser.parseOptionalAttrDict(result.attributes))
4339 result.addTypes(FIntegerType::get(context));
4341 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4342 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4343 properties.setValue(valueAttr);
4347ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4348 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4351 if (parser.parseOperandList(operands) ||
4352 parser.parseOptionalAttrDict(result.attributes) ||
4353 parser.parseColonType(type))
4355 result.addTypes(type);
4357 return parser.resolveOperands(operands, type.getElementType(),
4361void ListCreateOp::print(OpAsmPrinter &p) {
4363 p.printOperands(getElements());
4364 p.printOptionalAttrDict((*this)->getAttrs());
4365 p <<
" : " << getType();
4368LogicalResult ListCreateOp::verify() {
4369 if (getElements().
empty())
4372 auto elementType = getElements().front().getType();
4373 auto listElementType = getType().getElementType();
4375 return emitOpError(
"has elements of type ")
4376 <<
elementType <<
" instead of " << listElementType;
4381LogicalResult BundleCreateOp::verify() {
4382 BundleType resultType = getType();
4383 if (resultType.getNumElements() != getFields().size())
4384 return emitOpError(
"number of fields doesn't match type");
4385 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4387 resultType.getElementTypePreservingConst(i),
4388 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4389 return emitOpError(
"type of element doesn't match bundle for field ")
4390 << resultType.getElement(i).name;
4395LogicalResult VectorCreateOp::verify() {
4396 FVectorType resultType = getType();
4397 if (resultType.getNumElements() != getFields().size())
4398 return emitOpError(
"number of fields doesn't match type");
4399 auto elemTy = resultType.getElementTypePreservingConst();
4400 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4402 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4403 return emitOpError(
"type of element doesn't match vector element");
4412LogicalResult FEnumCreateOp::verify() {
4413 FEnumType resultType = getResult().getType();
4414 auto elementIndex = resultType.getElementIndex(
getFieldName());
4416 return emitOpError(
"label ")
4417 <<
getFieldName() <<
" is not a member of the enumeration type "
4420 resultType.getElementTypePreservingConst(*elementIndex),
4421 getInput().getType()))
4422 return emitOpError(
"type of element doesn't match enum element");
4426void FEnumCreateOp::print(OpAsmPrinter &printer) {
4429 printer <<
'(' << getInput() <<
')';
4430 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4431 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4433 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4434 ArrayRef<Type>{getResult().getType()});
4437ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4438 auto *context = parser.getContext();
4439 auto &properties = result.getOrAddProperties<Properties>();
4441 OpAsmParser::UnresolvedOperand input;
4442 std::string fieldName;
4443 mlir::FunctionType functionType;
4444 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4445 parser.parseOperand(input) || parser.parseRParen() ||
4446 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4447 parser.parseType(functionType))
4450 if (functionType.getNumInputs() != 1)
4451 return parser.emitError(parser.getNameLoc(),
"single input type required");
4452 if (functionType.getNumResults() != 1)
4453 return parser.emitError(parser.getNameLoc(),
"single result type required");
4455 auto inputType = functionType.getInput(0);
4456 if (parser.resolveOperand(input, inputType, result.operands))
4459 auto outputType = functionType.getResult(0);
4460 auto enumType = type_dyn_cast<FEnumType>(outputType);
4462 return parser.emitError(parser.getNameLoc(),
4463 "output must be enum type, got ")
4465 auto fieldIndex = enumType.getElementIndex(fieldName);
4467 return parser.emitError(parser.getNameLoc(),
4468 "unknown field " + fieldName +
" in enum type ")
4471 properties.setFieldIndex(
4472 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4474 result.addTypes(enumType);
4483LogicalResult IsTagOp::verify() {
4484 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4485 return emitOpError(
"element index is greater than the number of fields in "
4490void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4491 printer <<
' ' << getInput() <<
' ';
4493 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4494 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4495 printer <<
" : " << getInput().getType();
4498ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4499 auto *context = parser.getContext();
4500 auto &properties = result.getOrAddProperties<Properties>();
4502 OpAsmParser::UnresolvedOperand input;
4503 std::string fieldName;
4505 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4506 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4507 parser.parseType(inputType))
4510 if (parser.resolveOperand(input, inputType, result.operands))
4513 auto enumType = type_dyn_cast<FEnumType>(inputType);
4515 return parser.emitError(parser.getNameLoc(),
4516 "input must be enum type, got ")
4518 auto fieldIndex = enumType.getElementIndex(fieldName);
4520 return parser.emitError(parser.getNameLoc(),
4521 "unknown field " + fieldName +
" in enum type ")
4524 properties.setFieldIndex(
4525 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4527 result.addTypes(UIntType::get(context, 1,
false));
4532FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4533 OpaqueProperties properties,
4534 mlir::RegionRange regions,
4535 std::optional<Location> loc) {
4536 Adaptor adaptor(operands, attrs, properties, regions);
4537 return UIntType::get(attrs.getContext(), 1,
4538 isConst(adaptor.getInput().getType()));
4541template <
typename OpTy>
4543 auto *context = parser.getContext();
4545 OpAsmParser::UnresolvedOperand input;
4546 std::string fieldName;
4548 if (parser.parseOperand(input) || parser.parseLSquare() ||
4549 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4550 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4551 parser.parseType(inputType))
4554 if (parser.resolveOperand(input, inputType, result.operands))
4557 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4559 return parser.emitError(parser.getNameLoc(),
4560 "input must be bundle type, got ")
4562 auto fieldIndex = bundleType.getElementIndex(fieldName);
4564 return parser.emitError(parser.getNameLoc(),
4565 "unknown field " + fieldName +
" in bundle type ")
4568 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4569 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4571 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4574 result.addTypes(type);
4579ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4580 auto *context = parser.getContext();
4582 OpAsmParser::UnresolvedOperand input;
4583 std::string fieldName;
4585 if (parser.parseOperand(input) || parser.parseLSquare() ||
4586 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4587 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4588 parser.parseType(inputType))
4591 if (parser.resolveOperand(input, inputType, result.operands))
4594 auto enumType = type_dyn_cast<FEnumType>(inputType);
4596 return parser.emitError(parser.getNameLoc(),
4597 "input must be enum type, got ")
4599 auto fieldIndex = enumType.getElementIndex(fieldName);
4601 return parser.emitError(parser.getNameLoc(),
4602 "unknown field " + fieldName +
" in enum type ")
4605 result.getOrAddProperties<Properties>().setFieldIndex(
4606 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4608 SmallVector<Type> inferredReturnTypes;
4609 if (failed(SubtagOp::inferReturnTypes(
4610 context, result.location, result.operands,
4611 result.attributes.getDictionary(context), result.getRawProperties(),
4612 result.regions, inferredReturnTypes)))
4614 result.addTypes(inferredReturnTypes);
4619ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4620 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4622ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4623 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4626template <
typename OpTy>
4628 printer <<
' ' << op.getInput() <<
'[';
4629 printer.printKeywordOrString(op.getFieldName());
4631 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4632 elidedAttrs.push_back(
"fieldIndex");
4633 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4634 printer <<
" : " << op.getInput().getType();
4636void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4637 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4639void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4640 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4643void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4644 printer <<
' ' << getInput() <<
'[';
4647 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4648 elidedAttrs.push_back(
"fieldIndex");
4649 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4650 printer <<
" : " << getInput().getType();
4653template <
typename OpTy>
4655 if (op.getFieldIndex() >=
4656 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4658 return op.emitOpError(
"subfield element index is greater than the number "
4659 "of fields in the bundle type");
4662LogicalResult SubfieldOp::verify() {
4663 return verifySubfieldLike<SubfieldOp>(*
this);
4665LogicalResult OpenSubfieldOp::verify() {
4666 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4669LogicalResult SubtagOp::verify() {
4670 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4671 return emitOpError(
"subfield element index is greater than the number "
4672 "of fields in the bundle type");
4682 SmallVector<Operation *, 8> worklist({op});
4686 bool constant =
true;
4692 while (constant && !(worklist.empty()))
4693 TypeSwitch<Operation *>(worklist.pop_back_val())
4694 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4695 if (
auto definingOp = op.getInput().getDefiningOp())
4696 worklist.push_back(definingOp);
4699 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4700 for (
auto &use : op.getResult().getUses())
4701 worklist.push_back(use.getOwner());
4703 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4704 .Default([&](
auto) { constant =
false; });
4713 if (
auto *op = value.getDefiningOp())
4718LogicalResult ConstCastOp::verify() {
4720 return emitOpError() << getInput().getType()
4721 <<
" is not 'const'-castable to "
4722 << getResult().getType();
4726FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4727 std::optional<Location> loc) {
4728 auto inType = type_cast<BundleType>(type);
4730 if (fieldIndex >= inType.getNumElements())
4732 "subfield element index is greater than the "
4733 "number of fields in the bundle type");
4737 return inType.getElementTypePreservingConst(fieldIndex);
4740FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4741 std::optional<Location> loc) {
4742 auto inType = type_cast<OpenBundleType>(type);
4744 if (fieldIndex >= inType.getNumElements())
4746 "subfield element index is greater than the "
4747 "number of fields in the bundle type");
4751 return inType.getElementTypePreservingConst(fieldIndex);
4754bool SubfieldOp::isFieldFlipped() {
4755 BundleType bundle = getInput().getType();
4756 return bundle.getElement(getFieldIndex()).isFlip;
4758bool OpenSubfieldOp::isFieldFlipped() {
4759 auto bundle = getInput().getType();
4760 return bundle.getElement(getFieldIndex()).isFlip;
4763FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4764 std::optional<Location> loc) {
4765 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
4766 if (fieldIndex < vectorType.getNumElements())
4767 return vectorType.getElementTypePreservingConst();
4769 "' in vector type ", type);
4774FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4775 std::optional<Location> loc) {
4776 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
4777 if (fieldIndex < vectorType.getNumElements())
4778 return vectorType.getElementTypePreservingConst();
4780 "' in vector type ", type);
4786FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4787 OpaqueProperties properties,
4788 mlir::RegionRange regions,
4789 std::optional<Location> loc) {
4790 Adaptor adaptor(operands, attrs, properties, regions);
4791 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4792 auto fieldIndex = adaptor.getFieldIndex();
4794 if (fieldIndex >= inType.getNumElements())
4796 "subtag element index is greater than the "
4797 "number of fields in the enum type");
4801 auto elementType = inType.getElement(fieldIndex).type;
4805FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
4806 std::optional<Location> loc) {
4807 if (!type_isa<UIntType>(indexType))
4811 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4813 return vectorType.getElementTypePreservingConst();
4814 return vectorType.getElementType().getAllConstDroppedType();
4821FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4822 DictionaryAttr attrs,
4823 OpaqueProperties properties,
4824 mlir::RegionRange regions,
4825 std::optional<Location> loc) {
4826 Adaptor adaptor(operands, attrs, properties, regions);
4827 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4828 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4829 return UIntType::get(inType.getContext(), i);
4832ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4833 OpAsmParser::UnresolvedOperand index;
4834 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
4835 Type indexType, elemType;
4837 if (parser.parseOperand(index) || parser.parseComma() ||
4838 parser.parseOperandList(inputs) ||
4839 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4840 parser.parseType(indexType) || parser.parseComma() ||
4841 parser.parseType(elemType))
4844 if (parser.resolveOperand(index, indexType, result.operands))
4847 result.addTypes(elemType);
4849 return parser.resolveOperands(inputs, elemType, result.operands);
4852void MultibitMuxOp::print(OpAsmPrinter &p) {
4853 p <<
" " << getIndex() <<
", ";
4854 p.printOperands(getInputs());
4855 p.printOptionalAttrDict((*this)->getAttrs());
4856 p <<
" : " << getIndex().getType() <<
", " << getType();
4859FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4860 DictionaryAttr attrs,
4861 OpaqueProperties properties,
4862 mlir::RegionRange regions,
4863 std::optional<Location> loc) {
4864 if (operands.size() < 2)
4868 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4869 return operands[1].getType() == op.getType();
4873 return type_cast<FIRRTLType>(operands[1].getType());
4880LogicalResult ObjectSubfieldOp::inferReturnTypes(
4881 MLIRContext *context, std::optional<mlir::Location> location,
4882 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4883 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4885 inferReturnType(operands, attributes, properties, regions, location);
4888 inferredReturnTypes.push_back(type);
4892Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
4893 std::optional<Location> loc) {
4894 auto classType = dyn_cast<ClassType>(inType);
4898 if (classType.getNumElements() <= fieldIndex)
4900 "number of fields in the object");
4901 return classType.getElement(fieldIndex).type;
4904void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4905 auto input = getInput();
4906 auto classType = input.getType();
4907 p <<
' ' << input <<
"[";
4908 p.printKeywordOrString(classType.getElement(getIndex()).name);
4910 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4911 p <<
" : " << classType;
4914ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4915 OperationState &result) {
4916 auto *context = parser.getContext();
4918 OpAsmParser::UnresolvedOperand input;
4919 std::string fieldName;
4920 ClassType inputType;
4921 if (parser.parseOperand(input) || parser.parseLSquare() ||
4922 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4923 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4924 parser.parseType(inputType) ||
4925 parser.resolveOperand(input, inputType, result.operands))
4928 auto index = inputType.getElementIndex(fieldName);
4930 return parser.emitError(parser.getNameLoc(),
4931 "unknown field " + fieldName +
" in class type ")
4933 result.getOrAddProperties<Properties>().setIndex(
4934 IntegerAttr::get(IntegerType::get(context, 32), *index));
4936 SmallVector<Type> inferredReturnTypes;
4937 if (failed(inferReturnTypes(context, result.location, result.operands,
4938 result.attributes.getDictionary(context),
4939 result.getRawProperties(), result.regions,
4940 inferredReturnTypes)))
4942 result.addTypes(inferredReturnTypes);
4959 int32_t &rhsWidth,
bool &isConstResult,
4960 std::optional<Location> loc) {
4962 auto lhsi = type_dyn_cast<IntType>(lhs);
4963 auto rhsi = type_dyn_cast<IntType>(rhs);
4964 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4967 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4969 else if (!lhsi && rhsi)
4970 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4972 else if (!lhsi && !rhsi)
4973 mlir::emitError(*loc,
"operands must be integer types, not ")
4974 << lhs <<
" and " << rhs;
4976 mlir::emitError(*loc,
"operand signedness must match");
4981 lhsWidth = lhsi.getWidthOrSentinel();
4982 rhsWidth = rhsi.getWidthOrSentinel();
4983 isConstResult = lhsi.isConst() && rhsi.isConst();
4988 assert(op->getNumOperands() == 2 &&
4989 "SameOperandsIntTypeKind on non-binary op");
4990 int32_t lhsWidth, rhsWidth;
4993 op->getOperand(1).getType(), lhsWidth,
4994 rhsWidth, isConstResult, op->getLoc()));
4998 std::optional<Location> loc) {
4999 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5000 bool isConstResult =
false;
5004 if (lhsWidth != -1 && rhsWidth != -1)
5005 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5006 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5011 std::optional<Location> loc) {
5012 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5013 bool isConstResult =
false;
5017 if (lhsWidth != -1 && rhsWidth != -1)
5018 resultWidth = lhsWidth + rhsWidth;
5020 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5025 std::optional<Location> loc) {
5026 int32_t lhsWidth, rhsWidth;
5027 bool isConstResult =
false;
5032 if (type_isa<UIntType>(lhs))
5033 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5036 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5037 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5041 std::optional<Location> loc) {
5042 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5043 bool isConstResult =
false;
5047 if (lhsWidth != -1 && rhsWidth != -1)
5048 resultWidth = std::min(lhsWidth, rhsWidth);
5049 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5054 std::optional<Location> loc) {
5055 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5056 bool isConstResult =
false;
5060 if (lhsWidth != -1 && rhsWidth != -1) {
5061 resultWidth = std::max(lhsWidth, rhsWidth);
5062 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5065 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5069 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5073 std::optional<Location> loc) {
5074 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5077 auto lhsVec = type_cast<FVectorType>(lhs);
5078 auto rhsVec = type_cast<FVectorType>(rhs);
5080 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5085 rhsVec.getElementTypePreservingConst(), loc);
5088 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5089 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5090 lhsVec.isConst() && rhsVec.isConst() &&
5091 elemBaseType.isConst());
5095 std::optional<Location> loc) {
5096 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5100 std::optional<Location> loc) {
5101 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5102 bool isConstResult =
false;
5106 if (lhsWidth != -1 && rhsWidth != -1)
5107 resultWidth = lhsWidth + rhsWidth;
5108 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5112 std::optional<Location> loc) {
5113 auto lhsi = type_dyn_cast<IntType>(lhs);
5114 auto rhsui = type_dyn_cast<UIntType>(rhs);
5115 if (!rhsui || !lhsi)
5117 loc,
"first operand should be integer, second unsigned int");
5121 auto width = lhsi.getWidthOrSentinel();
5122 if (width == -1 || !rhsui.getWidth().has_value()) {
5125 auto amount = *rhsui.getWidth();
5128 "shift amount too large: second operand of "
5129 "dshl is wider than 31 bits");
5130 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5131 if (newWidth > INT32_MAX)
5133 loc,
"shift amount too large: first operand shifted by maximum "
5134 "amount exceeds maximum width");
5137 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5138 lhsi.
isConst() && rhsui.isConst());
5142 std::optional<Location> loc) {
5143 auto lhsi = type_dyn_cast<IntType>(lhs);
5144 auto rhsu = type_dyn_cast<UIntType>(rhs);
5147 loc,
"first operand should be integer, second unsigned int");
5148 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5152 std::optional<Location> loc) {
5153 auto lhsi = type_dyn_cast<IntType>(lhs);
5154 auto rhsu = type_dyn_cast<UIntType>(rhs);
5157 loc,
"first operand should be integer, second unsigned int");
5158 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5166 std::optional<Location> loc) {
5167 return UIntType::get(input.getContext(), 32);
5171 std::optional<Location> loc) {
5172 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5175 int32_t width = base.getBitWidthOrSentinel();
5178 return SIntType::get(input.getContext(), width, base.
isConst());
5182 std::optional<Location> loc) {
5183 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5186 int32_t width = base.getBitWidthOrSentinel();
5189 return UIntType::get(input.getContext(), width, base.
isConst());
5193 std::optional<Location> loc) {
5194 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5197 "operand must be single bit scalar base type");
5198 int32_t width = base.getBitWidthOrSentinel();
5199 if (width == -2 || width == 0 || width > 1)
5201 return AsyncResetType::get(input.getContext(), base.
isConst());
5205 std::optional<Location> loc) {
5206 return ClockType::get(input.getContext(),
isConst(input));
5210 std::optional<Location> loc) {
5211 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5212 auto width = uiType.getWidthOrSentinel();
5215 return SIntType::get(input.getContext(), width, uiType.
isConst());
5218 if (type_isa<SIntType>(input))
5225 std::optional<Location> loc) {
5226 auto inputi = type_dyn_cast<IntType>(input);
5229 int32_t width = inputi.getWidthOrSentinel();
5232 return SIntType::get(input.getContext(), width, inputi.
isConst());
5236 std::optional<Location> loc) {
5237 auto inputi = type_dyn_cast<IntType>(input);
5240 if (isa<UIntType>(inputi))
5242 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5247 std::optional<Location> loc) {
5248 return UIntType::get(input.getContext(), 1,
isConst(input));
5257 std::optional<Location> loc) {
5258 auto inputi = type_dyn_cast<IntType>(input);
5261 loc,
"input type should be the int type but got ", input);
5266 loc,
"high must be equal or greater than low, but got high = ", high,
5274 int32_t width = inputi.getWidthOrSentinel();
5275 if (width != -1 && high >= width)
5278 "high must be smaller than the width of input, but got high = ", high,
5279 ", width = ", width);
5281 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5285 std::optional<Location> loc) {
5287 auto inputi = type_dyn_cast<IntType>(input);
5288 if (amount < 0 || !inputi)
5290 loc,
"operand must have integer type and amount must be >= 0");
5292 int32_t width = inputi.getWidthOrSentinel();
5293 if (width != -1 && amount > width)
5296 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5311 bool isConstCondition,
5312 std::optional<Location> loc) {
5318 if (high.getTypeID() != low.getTypeID())
5319 return emitInferRetTypeError<FIRRTLBaseType>(
5320 loc,
"incompatible mux operand types, true value type: ", high,
5321 ", false value type: ", low);
5323 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5328 if (type_isa<IntType>(low)) {
5333 if (highWidth == -1)
5335 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5339 auto highVector = type_dyn_cast<FVectorType>(high);
5340 auto lowVector = type_dyn_cast<FVectorType>(low);
5341 if (highVector && lowVector &&
5342 highVector.getNumElements() == lowVector.getNumElements()) {
5344 lowVector.getElementTypePreservingConst(),
5345 isConstCondition, loc);
5348 return FVectorType::get(inner, lowVector.getNumElements(),
5353 auto highBundle = type_dyn_cast<BundleType>(high);
5354 auto lowBundle = type_dyn_cast<BundleType>(low);
5355 if (highBundle && lowBundle) {
5356 auto highElements = highBundle.getElements();
5357 auto lowElements = lowBundle.getElements();
5360 SmallVector<BundleType::BundleElement> newElements;
5362 bool failed =
false;
5364 if (highElements[i].name != lowElements[i].name ||
5365 highElements[i].isFlip != lowElements[i].isFlip) {
5369 auto element = highElements[i];
5371 highBundle.getElementTypePreservingConst(i),
5372 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5375 newElements.push_back(element);
5378 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5380 return emitInferRetTypeError<FIRRTLBaseType>(
5381 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5382 ", false value type: ", low);
5387 return emitInferRetTypeError<FIRRTLBaseType>(
5388 loc,
"invalid mux operand types, true value type: ", high,
5389 ", false value type: ", low);
5394 std::optional<Location> loc) {
5395 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5396 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5397 if (!highType || !lowType)
5402FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5403 DictionaryAttr attrs,
5404 OpaqueProperties properties,
5405 mlir::RegionRange regions,
5406 std::optional<Location> loc) {
5407 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5408 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5409 if (!highType || !lowType)
5415FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5416 DictionaryAttr attrs,
5417 OpaqueProperties properties,
5418 mlir::RegionRange regions,
5419 std::optional<Location> loc) {
5420 SmallVector<FIRRTLBaseType> types;
5422 for (
unsigned i = 1; i < 5; i++) {
5423 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5428 isConst(operands[0].getType()), loc);
5432 result = types.back();
5439 std::optional<Location> loc) {
5440 auto inputi = type_dyn_cast<IntType>(input);
5441 if (amount < 0 || !inputi)
5443 loc,
"pad input must be integer and amount must be >= 0");
5445 int32_t width = inputi.getWidthOrSentinel();
5449 width = std::max<int32_t>(width, amount);
5450 return IntType::get(input.getContext(), inputi.isSigned(), width,
5455 std::optional<Location> loc) {
5456 auto inputi = type_dyn_cast<IntType>(input);
5457 if (amount < 0 || !inputi)
5459 loc,
"shl input must be integer and amount must be >= 0");
5461 int32_t width = inputi.getWidthOrSentinel();
5465 return IntType::get(input.getContext(), inputi.isSigned(), width,
5470 std::optional<Location> loc) {
5471 auto inputi = type_dyn_cast<IntType>(input);
5472 if (amount < 0 || !inputi)
5474 loc,
"shr input must be integer and amount must be >= 0");
5476 int32_t width = inputi.getWidthOrSentinel();
5479 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5480 width = std::max<int32_t>(minWidth, width - amount);
5483 return IntType::get(input.getContext(), inputi.isSigned(), width,
5488 std::optional<Location> loc) {
5490 auto inputi = type_dyn_cast<IntType>(input);
5491 if (amount < 0 || !inputi)
5493 loc,
"tail input must be integer and amount must be >= 0");
5495 int32_t width = inputi.getWidthOrSentinel();
5499 loc,
"amount must be less than or equal operand width");
5510void VerbatimExprOp::getAsmResultNames(
5511 function_ref<
void(Value, StringRef)> setNameFn) {
5515 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5516 auto name = getText();
5518 if (name.starts_with(
"`"))
5519 name = name.drop_front();
5520 name = name.take_while(isOkCharacter);
5522 setNameFn(getResult(), name);
5529void VerbatimWireOp::getAsmResultNames(
5530 function_ref<
void(Value, StringRef)> setNameFn) {
5534 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5535 auto name = getText();
5537 if (name.starts_with(
"`"))
5538 name = name.drop_front();
5539 name = name.take_while(isOkCharacter);
5541 setNameFn(getResult(), name);
5552 op->emitError() <<
"unknown width is not allowed for DPI";
5553 return WalkResult::interrupt();
5555 if (width == 1 || width == 8 || width == 16 || width == 32 ||
5557 return WalkResult::advance();
5559 <<
"integer types used by DPI functions must have a "
5560 "specific bit width; "
5561 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5562 "32(int), 64(longint) "
5563 "or greater than 64, but got "
5565 return WalkResult::interrupt();
5570LogicalResult DPICallIntrinsicOp::verify() {
5571 if (
auto inputNames = getInputNames()) {
5572 if (getInputs().size() != inputNames->size())
5573 return emitError() <<
"inputNames has " << inputNames->size()
5574 <<
" elements but there are " << getInputs().size()
5575 <<
" input arguments";
5577 if (
auto outputName = getOutputName())
5578 if (getNumResults() == 0)
5579 return emitError() <<
"output name is given but there is no result";
5581 auto checkType = [
this](Type type) {
5584 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5585 llvm::all_of(this->getOperandTypes(), checkType));
5588SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5589DPICallIntrinsicOp::computeDataFlow() {
5593 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5595 for (
auto operand : getOperands()) {
5596 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5598 SmallVector<circt::FieldRef> operandFields;
5601 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5605 for (
auto result : getResults())
5608 for (
auto field : operandFields)
5609 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
5619LogicalResult HWStructCastOp::verify() {
5621 BundleType bundleType;
5622 hw::StructType structType;
5623 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5624 structType = dyn_cast<hw::StructType>(getType());
5626 return emitError(
"result type must be a struct");
5627 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5628 structType = dyn_cast<hw::StructType>(getOperand().getType());
5630 return emitError(
"operand type must be a struct");
5632 return emitError(
"either source or result type must be a bundle type");
5635 auto firFields = bundleType.getElements();
5636 auto hwFields = structType.getElements();
5637 if (firFields.size() != hwFields.size())
5638 return emitError(
"bundle and struct have different number of fields");
5640 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5641 if (firFields[findex].name.getValue() != hwFields[findex].name)
5642 return emitError(
"field names don't match '")
5643 << firFields[findex].name.getValue() <<
"', '"
5644 << hwFields[findex].name.getValue() <<
"'";
5648 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5649 return emitError(
"size of field '")
5650 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5657LogicalResult BitCastOp::verify() {
5658 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5660 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5662 if (*inTypeBits == *resTypeBits) {
5665 return emitError(
"cannot cast non-'const' input type ")
5666 << getOperand().getType() <<
" to 'const' result type "
5670 return emitError(
"the bitwidth of input (")
5671 << *inTypeBits <<
") and result (" << *resTypeBits
5674 if (!inTypeBits.has_value())
5675 return emitError(
"bitwidth cannot be determined for input operand type ")
5676 << getInput().getType();
5677 return emitError(
"bitwidth cannot be determined for result type ")
5688 NamedAttrList &resultAttrs) {
5689 auto result = parser.parseOptionalAttrDict(resultAttrs);
5690 if (!resultAttrs.get(
"annotations"))
5691 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5697 DictionaryAttr attr,
5698 ArrayRef<StringRef> extraElides = {}) {
5699 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5701 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5702 elidedAttrs.push_back(
"annotations");
5704 elidedAttrs.push_back(
"nameKind");
5706 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5712 NamedAttrList &resultAttrs) {
5715 if (!resultAttrs.get(
"portAnnotations")) {
5716 SmallVector<Attribute, 16> portAnnotations(
5717 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5718 resultAttrs.append(
"portAnnotations",
5719 parser.getBuilder().getArrayAttr(portAnnotations));
5726 DictionaryAttr attr,
5727 ArrayRef<StringRef> extraElides = {}) {
5728 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5730 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5731 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5732 elidedAttrs.push_back(
"portAnnotations");
5741 firrtl::NameKindEnumAttr &result) {
5744 if (!parser.parseOptionalKeyword(&keyword,
5745 {
"interesting_name",
"droppable_name"})) {
5746 auto kind = symbolizeNameKindEnum(keyword);
5747 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
5753 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
5758 firrtl::NameKindEnumAttr attr,
5759 ArrayRef<StringRef> extraElides = {}) {
5760 if (attr.getValue() != NameKindEnum::DroppableName)
5761 p <<
" " << stringifyNameKindEnum(attr.getValue());
5769 NamedAttrList &resultAttrs) {
5777 DictionaryAttr attrs) {
5778 SmallVector<StringRef, 4> elides;
5780 elides.push_back(Forceable::getForceableAttrName());
5789static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5789static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
…}
5794static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5794static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
…}
5805 if (ClassType::parseInterface(parser, type))
5812 type.printInterface(p);
5820 NamedAttrList &resultAttrs) {
5821 auto result = p.parseOptionalAttrDict(resultAttrs);
5822 if (!resultAttrs.get(
"name"))
5823 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5829 DictionaryAttr attr,
5830 ArrayRef<StringRef> extraElides = {}) {
5831 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5832 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5833 elides.push_back(
"name");
5835 p.printOptionalAttrDict(op->getAttrs(), elides);
5839 NamedAttrList &resultAttrs) {
5844 DictionaryAttr attr) {
5849 NamedAttrList &resultAttrs) {
5854 DictionaryAttr attr) {
5863 DictionaryAttr attr) {
5872 DictionaryAttr attr) {
5881 OpAsmSetValueNameFn setNameFn) {
5884 if (op->getNumResults() == 1)
5885 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5886 setNameFn(op->getResult(0), nameAttr.getValue());
5889void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5893void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5897void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5901void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5904void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5907void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5910void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5913void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5916void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5919void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5922void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5925void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5928void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5931void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5934void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5937void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5940void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5943void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5946void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5949void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5952void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5955void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5958void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5961void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5964void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5967void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5970void PlusArgsValueIntrinsicOp::getAsmResultNames(
5971 OpAsmSetValueNameFn setNameFn) {
5974void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5977void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5980void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5983void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5986void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5989void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5992void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5995void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5998void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6001void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6004void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6007void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6010void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6013void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6016void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6019void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6022void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6026void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6030void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6034void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6038void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6042void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6046void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6050void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6054void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6058void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6062void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6066void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6070void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6074void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6078void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6082void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6086void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6094void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6098void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6102void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6106void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6110void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6114FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6115 DictionaryAttr attrs,
6116 OpaqueProperties properties,
6117 mlir::RegionRange regions,
6118 std::optional<Location> loc) {
6119 Type inType = operands[0].getType();
6120 auto inRefType = type_dyn_cast<RefType>(inType);
6123 loc,
"ref.resolve operand must be ref type, not ", inType);
6124 return inRefType.getType();
6127FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6128 OpaqueProperties properties,
6129 mlir::RegionRange regions,
6130 std::optional<Location> loc) {
6131 Type inType = operands[0].getType();
6132 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6135 loc,
"ref.send operand must be base type, not ", inType);
6136 return RefType::get(inBaseType.getPassiveType());
6139FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6140 std::optional<Location> loc) {
6141 auto refType = type_dyn_cast<RefType>(type);
6144 auto inType = refType.getType();
6150 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6151 if (fieldIndex < vectorType.getNumElements())
6152 return RefType::get(
6153 vectorType.getElementType().getConstType(
6154 vectorType.isConst() || vectorType.getElementType().isConst()),
6155 refType.getForceable(), refType.getLayer());
6157 "' in RefType of vector type ", refType);
6159 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6160 if (fieldIndex >= bundleType.getNumElements()) {
6162 "subfield element index is greater than "
6163 "the number of fields in the bundle type");
6165 return RefType::get(
6166 bundleType.getElement(fieldIndex)
6168 bundleType.isConst() ||
6169 bundleType.getElement(fieldIndex).type.isConst()),
6170 refType.getForceable(), refType.getLayer());
6174 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6177LogicalResult RefCastOp::verify() {
6180 SmallVector<SymbolRefAttr> missingLayers;
6183 emitOpError(
"cannot discard layer requirements of input reference");
6184 auto ¬e = diag.attachNote();
6185 note <<
"discarding layer requirements: ";
6186 llvm::interleaveComma(missingLayers, note);
6192LogicalResult RefResolveOp::verify() {
6195 SmallVector<SymbolRefAttr> missingLayers;
6198 emitOpError(
"ambient layers are insufficient to resolve reference");
6199 auto ¬e = diag.attachNote();
6200 note <<
"missing layer requirements: ";
6201 interleaveComma(missingLayers, note);
6208 auto targetRef = getTarget();
6209 if (targetRef.getModule() !=
6210 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6211 return emitOpError() <<
"has non-local target";
6213 auto target = ns.
lookup(targetRef);
6215 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6217 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6222 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6223 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6224 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6225 << fType <<
" instead of expected " << getType().getType();
6226 diag.attachNote(loc) <<
"target resolves here";
6232 auto checkLayers = [&](Location loc) -> LogicalResult {
6235 SmallVector<SymbolRefAttr> missingLayers;
6237 auto diag = emitOpError(
"target has insufficient layer requirements");
6238 auto ¬e = diag.attachNote(loc);
6239 note <<
"target is missing layer requirements: ";
6240 llvm::interleaveComma(missingLayers, note);
6245 auto checks = [&](
auto type, Location loc) {
6246 if (failed(checkLayers(loc)))
6248 return checkFinalType(type, loc);
6251 if (target.isPort()) {
6252 auto mod = cast<FModuleLike>(target.getOp());
6253 return checks(mod.getPortType(target.getPort()),
6254 mod.getPortLocation(target.getPort()));
6256 hw::InnerSymbolOpInterface symOp =
6257 cast<hw::InnerSymbolOpInterface>(target.getOp());
6258 if (!symOp.getTargetResult())
6259 return emitOpError(
"has target that cannot be probed")
6260 .attachNote(symOp.getLoc())
6261 .append(
"target resolves here");
6263 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6264 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6265 return emitOpError(
"is not dominated by target")
6266 .attachNote(symOp.getLoc())
6267 .append(
"target here");
6268 return checks(symOp.getTargetResult().getType(), symOp.getLoc());
6275LogicalResult LayerBlockOp::verify() {
6276 auto layerName = getLayerName();
6277 auto *parentOp = (*this)->getParentOp();
6280 while (isa<WhenOp, MatchOp>(parentOp))
6281 parentOp = parentOp->getParentOp();
6285 auto nestedReferences = layerName.getNestedReferences();
6286 if (nestedReferences.empty()) {
6287 if (!isa<FModuleOp>(parentOp)) {
6288 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6289 "not have a 'firrtl.module' op as a parent";
6290 return diag.attachNote(parentOp->getLoc())
6291 <<
"illegal parent op defined here";
6294 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6295 if (!parentLayerBlock) {
6296 auto diag = emitOpError()
6297 <<
"has a nested layer symbol, but does not have a '"
6298 << getOperationName() <<
"' op as a parent'";
6299 return diag.attachNote(parentOp->getLoc())
6300 <<
"illegal parent op defined here";
6302 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6303 if (parentLayerBlockName.getRootReference() !=
6304 layerName.getRootReference() ||
6305 parentLayerBlockName.getNestedReferences() !=
6306 layerName.getNestedReferences().drop_back()) {
6307 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6308 return diag.attachNote(parentLayerBlock->getLoc())
6309 <<
"illegal parent layer block defined here";
6315 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6316 [&](Operation *op) -> WalkResult {
6318 if (isa<LayerBlockOp>(op))
6319 return WalkResult::skip();
6323 for (
auto operand : op->getOperands()) {
6325 if (
auto *definingOp = operand.getDefiningOp())
6329 auto type = operand.getType();
6332 if (isa<PropertyType>(type)) {
6333 auto diag = emitOpError() <<
"captures a property operand";
6334 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6335 diag.attachNote(op->getLoc()) <<
"operand is used here";
6336 return WalkResult::interrupt();
6341 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6343 if (isa<RefDefineOp>(connect))
6344 return WalkResult::advance();
6351 bool passive =
true;
6353 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6354 passive = type.isPassive();
6363 return WalkResult::advance();
6366 return WalkResult::advance();
6370 <<
"connects to a destination which is defined outside its "
6371 "enclosing layer block";
6372 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6373 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6374 return WalkResult::interrupt();
6377 return WalkResult::advance();
6380 return failure(result.wasInterrupted());
6384LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6386 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6388 return emitOpError(
"invalid symbol reference");
6398void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6399 setNameFn(getResult(),
"time");
6402void HierarchicalModuleNameOp::getAsmResultNames(
6403 OpAsmSetValueNameFn setNameFn) {
6404 setNameFn(getResult(),
"hierarchicalmodulename");
6412 auto ref = getInstanceAttr();
6413 auto target = ns.
lookup(ref);
6415 return emitError() <<
"target " << ref <<
" cannot be resolved";
6417 if (!target.isOpOnly())
6418 return emitError() <<
"target " << ref <<
" is not an operation";
6420 auto instance = dyn_cast<InstanceOp>(target.getOp());
6422 return emitError() <<
"target " << ref <<
" is not an instance";
6424 if (!instance.getDoNotPrint())
6425 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
6435#define GET_OP_CLASSES
6436#include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
static bool isAncestor(Block *block, Block *other)
static void printNameKind(OpAsmPrinter &p, Operation *op, firrtl::NameKindEnumAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static 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< PortInfo > getPortImpl(FModuleLike module)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void eraseInternalPaths(T op, const llvm::BitVector &portIndices)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static 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 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 ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports, bool supportsInternalPaths=false)
Inserts the given ports.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void 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 ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static 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)
const char * toString(Flow flow)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
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.
ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static bool isTypeAllowedForDPI(Operation *op, Type type)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static InstancePath empty
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
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.
Caching version of getFieldRefFromValue.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Caching version of getFieldRefFromValue.
This is the common base class between SIntType and UIntType.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
bool hasWidth() const
Return true if this integer type has a known width.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
connect(destination, source)
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * dutAnnoClass
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.