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));
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(
2221 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2222 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2223 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2224 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2225 ArrayRef<Attribute> layers,
bool lowerToBind, StringAttr innerSym) {
2226 build(builder, result, resultTypes, moduleName, name, nameKind,
2227 portDirections, portNames, annotations, portAnnotations, layers,
2229 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2232void InstanceOp::build(
2233 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2234 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2235 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2236 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2237 ArrayRef<Attribute> layers,
bool lowerToBind, hw::InnerSymAttr innerSym) {
2238 result.addTypes(resultTypes);
2239 result.getOrAddProperties<Properties>().setModuleName(
2240 SymbolRefAttr::get(builder.getContext(), moduleName));
2241 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2242 result.getOrAddProperties<Properties>().setPortDirections(
2244 result.getOrAddProperties<Properties>().setPortNames(
2245 builder.getArrayAttr(portNames));
2246 result.getOrAddProperties<Properties>().setAnnotations(
2247 builder.getArrayAttr(annotations));
2248 result.getOrAddProperties<Properties>().setLayers(
2249 builder.getArrayAttr(layers));
2251 result.getOrAddProperties<Properties>().setLowerToBind(
2252 builder.getUnitAttr());
2254 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2256 result.getOrAddProperties<Properties>().setNameKind(
2257 NameKindEnumAttr::get(builder.getContext(), nameKind));
2259 if (portAnnotations.empty()) {
2260 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2261 builder.getArrayAttr({}));
2262 result.getOrAddProperties<Properties>().setPortAnnotations(
2263 builder.getArrayAttr(portAnnotationsVec));
2265 assert(portAnnotations.size() == resultTypes.size());
2266 result.getOrAddProperties<Properties>().setPortAnnotations(
2267 builder.getArrayAttr(portAnnotations));
2271void InstanceOp::build(OpBuilder &builder, OperationState &result,
2272 FModuleLike module, StringRef name,
2273 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2274 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2275 hw::InnerSymAttr innerSym) {
2278 SmallVector<Type> resultTypes;
2279 resultTypes.reserve(module.getNumPorts());
2281 module.getPortTypes(), std::back_inserter(resultTypes),
2282 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2285 ArrayAttr portAnnotationsAttr;
2286 if (portAnnotations.empty()) {
2287 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2288 resultTypes.size(), builder.getArrayAttr({})));
2290 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2294 builder, result, resultTypes,
2295 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2296 builder.getStringAttr(name),
2297 NameKindEnumAttr::get(builder.getContext(), nameKind),
2298 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2299 builder.getArrayAttr(annotations), portAnnotationsAttr,
2300 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2304void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2305 ArrayRef<PortInfo> ports, StringRef moduleName,
2306 StringRef name, NameKindEnum nameKind,
2307 ArrayRef<Attribute> annotations,
2308 ArrayRef<Attribute> layers,
bool lowerToBind,
2309 hw::InnerSymAttr innerSym) {
2311 SmallVector<Type> newResultTypes;
2312 SmallVector<Direction> newPortDirections;
2313 SmallVector<Attribute> newPortNames;
2314 SmallVector<Attribute> newPortAnnotations;
2315 for (
auto &p : ports) {
2316 newResultTypes.push_back(p.type);
2317 newPortDirections.push_back(p.direction);
2318 newPortNames.push_back(p.name);
2319 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2322 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2323 newPortDirections, newPortNames, annotations, newPortAnnotations,
2324 layers, lowerToBind, innerSym);
2327LogicalResult InstanceOp::verify() {
2330 SmallVector<SymbolRefAttr> missingLayers;
2331 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2333 missingLayers.push_back(layer);
2335 if (missingLayers.empty())
2339 emitOpError(
"ambient layers are insufficient to instantiate module");
2340 auto ¬e = diag.attachNote();
2341 note <<
"missing layer requirements: ";
2342 interleaveComma(missingLayers, note);
2348InstanceOp InstanceOp::erasePorts(OpBuilder &builder,
2349 const llvm::BitVector &portIndices) {
2350 assert(portIndices.size() >= getNumResults() &&
2351 "portIndices is not at least as large as getNumResults()");
2353 if (portIndices.none())
2356 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2357 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2358 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2360 SmallVector<Attribute> newPortNames =
2362 SmallVector<Attribute> newPortAnnotations =
2365 auto newOp = builder.create<InstanceOp>(
2366 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2367 newPortDirections, newPortNames, getAnnotations().getValue(),
2368 newPortAnnotations, getLayers(), getLowerToBind(), getInnerSymAttr());
2370 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2371 oldIdx != numOldPorts; ++oldIdx) {
2372 if (portIndices.test(oldIdx)) {
2373 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2376 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2384 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2385 newOp->setAttr(
"output_file", outputFile);
2390ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2391 assert(portIdx < getNumResults() &&
2392 "index should be smaller than result number");
2393 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2396void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2397 assert(annotations.size() == getNumResults() &&
2398 "number of annotations is not equal to result number");
2399 (*this)->setAttr(
"portAnnotations",
2400 ArrayAttr::get(getContext(), annotations));
2404InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2405 auto portSize = ports.size();
2406 auto newPortCount = getNumResults() + portSize;
2407 SmallVector<Direction> newPortDirections;
2408 newPortDirections.reserve(newPortCount);
2409 SmallVector<Attribute> newPortNames;
2410 newPortNames.reserve(newPortCount);
2411 SmallVector<Type> newPortTypes;
2412 newPortTypes.reserve(newPortCount);
2413 SmallVector<Attribute> newPortAnnos;
2414 newPortAnnos.reserve(newPortCount);
2416 unsigned oldIndex = 0;
2417 unsigned newIndex = 0;
2418 while (oldIndex + newIndex < newPortCount) {
2420 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2421 auto &newPort = ports[newIndex].second;
2422 newPortDirections.push_back(newPort.direction);
2423 newPortNames.push_back(newPort.name);
2424 newPortTypes.push_back(newPort.type);
2425 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2429 newPortDirections.push_back(getPortDirection(oldIndex));
2430 newPortNames.push_back(getPortName(oldIndex));
2431 newPortTypes.push_back(getType(oldIndex));
2432 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2438 return OpBuilder(*this).create<InstanceOp>(
2439 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2440 newPortDirections, newPortNames, getAnnotations().getValue(),
2441 newPortAnnos, getLayers(), getLowerToBind(), getInnerSymAttr());
2444LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2446 getModuleNameAttr());
2449StringRef InstanceOp::getInstanceName() {
return getName(); }
2451StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2453void InstanceOp::print(OpAsmPrinter &p) {
2456 p.printKeywordOrString(
getName());
2457 if (
auto attr = getInnerSymAttr()) {
2459 p.printSymbolName(attr.getSymName());
2461 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2462 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2465 SmallVector<StringRef, 10> omittedAttrs = {
2466 "moduleName",
"name",
"portDirections",
2467 "portNames",
"portTypes",
"portAnnotations",
2468 "inner_sym",
"nameKind"};
2469 if (getAnnotations().
empty())
2470 omittedAttrs.push_back(
"annotations");
2471 if (getLayers().
empty())
2472 omittedAttrs.push_back(
"layers");
2473 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2477 p.printSymbolName(getModuleName());
2480 SmallVector<Attribute> portTypes;
2481 portTypes.reserve(getNumResults());
2482 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2485 getPortNames().getValue(), portTypes,
2486 getPortAnnotations().getValue(), {}, {});
2489ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2490 auto *context = parser.getContext();
2491 auto &properties = result.getOrAddProperties<Properties>();
2494 hw::InnerSymAttr innerSymAttr;
2495 FlatSymbolRefAttr moduleName;
2496 SmallVector<OpAsmParser::Argument> entryArgs;
2497 SmallVector<Direction, 4> portDirections;
2498 SmallVector<Attribute, 4> portNames;
2499 SmallVector<Attribute, 4> portTypes;
2500 SmallVector<Attribute, 4> portAnnotations;
2501 SmallVector<Attribute, 4> portSyms;
2502 SmallVector<Attribute, 4> portLocs;
2503 NameKindEnumAttr nameKind;
2505 if (parser.parseKeywordOrString(&name))
2507 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2508 if (parser.parseCustomAttributeWithFallback(
2509 innerSymAttr, ::mlir::Type{},
2511 result.attributes)) {
2512 return ::mlir::failure();
2516 parser.parseOptionalAttrDict(result.attributes) ||
2517 parser.parseAttribute(moduleName) ||
2519 false, entryArgs, portDirections,
2520 portNames, portTypes, portAnnotations, portSyms,
2527 properties.setModuleName(moduleName);
2528 properties.setName(StringAttr::get(context, name));
2529 properties.setNameKind(nameKind);
2530 properties.setPortDirections(
2532 properties.setPortNames(ArrayAttr::get(context, portNames));
2533 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2537 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2538 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2541 result.types.reserve(portTypes.size());
2543 portTypes, std::back_inserter(result.types),
2544 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2549void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2554 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2555 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2559std::optional<size_t> InstanceOp::getTargetResultIndex() {
2561 return std::nullopt;
2568void InstanceChoiceOp::build(
2569 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2570 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2571 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2572 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2574 SmallVector<Type> resultTypes;
2575 for (Attribute portType : defaultModule.getPortTypes())
2576 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2579 ArrayAttr portAnnotationsAttr;
2580 if (portAnnotations.empty()) {
2581 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2582 resultTypes.size(), builder.getArrayAttr({})));
2584 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2588 SmallVector<Attribute> moduleNames, caseNames;
2589 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2590 for (
auto [caseOption, caseModule] : cases) {
2591 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2592 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2593 {SymbolRefAttr::get(caseOption)}));
2594 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2597 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2598 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2599 NameKindEnumAttr::get(builder.getContext(), nameKind),
2600 defaultModule.getPortDirectionsAttr(),
2601 defaultModule.getPortNamesAttr(),
2602 builder.getArrayAttr(annotations), portAnnotationsAttr,
2603 defaultModule.getLayersAttr(),
2604 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2607std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2608 return std::nullopt;
2611void InstanceChoiceOp::print(OpAsmPrinter &p) {
2614 p.printKeywordOrString(
getName());
2615 if (
auto attr = getInnerSymAttr()) {
2617 p.printSymbolName(attr.getSymName());
2619 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2620 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2623 SmallVector<StringRef, 10> omittedAttrs = {
2624 "moduleNames",
"caseNames",
"name",
2625 "portDirections",
"portNames",
"portTypes",
2626 "portAnnotations",
"inner_sym",
"nameKind"};
2627 if (getAnnotations().
empty())
2628 omittedAttrs.push_back(
"annotations");
2629 if (getLayers().
empty())
2630 omittedAttrs.push_back(
"layers");
2631 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2636 auto moduleNames = getModuleNamesAttr();
2637 auto caseNames = getCaseNamesAttr();
2639 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2641 p <<
" alternatives ";
2643 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2645 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2649 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2650 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2652 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2658 SmallVector<Attribute> portTypes;
2659 portTypes.reserve(getNumResults());
2660 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2663 getPortNames().getValue(), portTypes,
2664 getPortAnnotations().getValue(), {}, {});
2667ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2668 OperationState &result) {
2669 auto *context = parser.getContext();
2670 auto &properties = result.getOrAddProperties<Properties>();
2673 hw::InnerSymAttr innerSymAttr;
2674 SmallVector<Attribute> moduleNames;
2675 SmallVector<Attribute> caseNames;
2676 SmallVector<OpAsmParser::Argument> entryArgs;
2677 SmallVector<Direction, 4> portDirections;
2678 SmallVector<Attribute, 4> portNames;
2679 SmallVector<Attribute, 4> portTypes;
2680 SmallVector<Attribute, 4> portAnnotations;
2681 SmallVector<Attribute, 4> portSyms;
2682 SmallVector<Attribute, 4> portLocs;
2683 NameKindEnumAttr nameKind;
2685 if (parser.parseKeywordOrString(&name))
2687 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2688 if (parser.parseCustomAttributeWithFallback(
2689 innerSymAttr, Type{},
2691 result.attributes)) {
2696 parser.parseOptionalAttrDict(result.attributes))
2699 FlatSymbolRefAttr defaultModuleName;
2700 if (parser.parseAttribute(defaultModuleName))
2702 moduleNames.push_back(defaultModuleName);
2706 FlatSymbolRefAttr optionName;
2707 if (parser.parseKeyword(
"alternatives") ||
2708 parser.parseAttribute(optionName) || parser.parseLBrace())
2711 FlatSymbolRefAttr moduleName;
2712 StringAttr caseName;
2713 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2714 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2716 moduleNames.push_back(moduleName);
2717 caseNames.push_back(SymbolRefAttr::get(
2718 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2719 if (failed(parser.parseOptionalComma()))
2722 if (parser.parseRBrace())
2727 false, entryArgs, portDirections,
2728 portNames, portTypes, portAnnotations, portSyms,
2734 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
2735 properties.setCaseNames(ArrayAttr::get(context, caseNames));
2736 properties.setName(StringAttr::get(context, name));
2737 properties.setNameKind(nameKind);
2738 properties.setPortDirections(
2740 properties.setPortNames(ArrayAttr::get(context, portNames));
2741 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2745 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2746 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2749 result.types.reserve(portTypes.size());
2751 portTypes, std::back_inserter(result.types),
2752 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2757void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2759 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
2760 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
2763LogicalResult InstanceChoiceOp::verify() {
2764 if (getCaseNamesAttr().
empty())
2765 return emitOpError() <<
"must have at least one case";
2766 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2767 return emitOpError() <<
"number of referenced modules does not match the "
2768 "number of options";
2773 SmallVector<SymbolRefAttr> missingLayers;
2774 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2776 missingLayers.push_back(layer);
2778 if (missingLayers.empty())
2782 emitOpError(
"ambient layers are insufficient to instantiate module");
2783 auto ¬e = diag.attachNote();
2784 note <<
"missing layer requirements: ";
2785 interleaveComma(missingLayers, note);
2790InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2791 auto caseNames = getCaseNamesAttr();
2792 for (
auto moduleName : getModuleNamesAttr()) {
2794 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
2798 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
2799 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2800 auto ref = cast<SymbolRefAttr>(caseNames[i]);
2801 auto refRoot = ref.getRootReference();
2802 if (ref.getRootReference() != root)
2803 return emitOpError() <<
"case " << ref
2804 <<
" is not in the same option group as "
2807 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2808 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2810 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2811 return emitOpError() <<
"option " << refRoot
2812 <<
" does not contain option case " << ref;
2819InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2820 auto caseNames = getCaseNamesAttr();
2821 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2822 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
2823 if (caseSym == option.getSymName())
2824 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
2826 return getDefaultTargetAttr();
2829SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2830InstanceChoiceOp::getTargetChoices() {
2831 auto caseNames = getCaseNamesAttr();
2832 auto moduleNames = getModuleNamesAttr();
2833 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2834 for (
size_t i = 0; i < caseNames.size(); ++i) {
2835 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
2836 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
2843InstanceChoiceOp::erasePorts(OpBuilder &builder,
2844 const llvm::BitVector &portIndices) {
2845 assert(portIndices.size() >= getNumResults() &&
2846 "portIndices is not at least as large as getNumResults()");
2848 if (portIndices.none())
2851 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2852 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2853 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2855 SmallVector<Attribute> newPortNames =
2857 SmallVector<Attribute> newPortAnnotations =
2860 auto newOp = builder.create<InstanceChoiceOp>(
2861 getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
getName(),
2863 ArrayAttr::get(getContext(), newPortNames), getAnnotationsAttr(),
2864 ArrayAttr::get(getContext(), newPortAnnotations), getLayers(),
2867 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2868 oldIdx != numOldPorts; ++oldIdx) {
2869 if (portIndices.test(oldIdx)) {
2870 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2873 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2881 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2882 newOp->setAttr(
"output_file", outputFile);
2891ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2892 assert(portIdx < getNumResults() &&
2893 "index should be smaller than result number");
2894 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2897void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2898 assert(annotations.size() == getNumResults() &&
2899 "number of annotations is not equal to result number");
2900 (*this)->setAttr(
"portAnnotations",
2901 ArrayAttr::get(getContext(), annotations));
2905void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
2906 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2909 numReadWritePorts = 0;
2911 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2912 auto portKind = getPortKind(i);
2913 if (portKind == MemOp::PortKind::Debug)
2915 else if (portKind == MemOp::PortKind::Read)
2917 else if (portKind == MemOp::PortKind::Write) {
2920 ++numReadWritePorts;
2925LogicalResult MemOp::verify() {
2929 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2935 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2936 auto portName = getPortName(i);
2941 BundleType portBundleType =
2942 type_dyn_cast<BundleType>(getResult(i).getType());
2945 if (!portNamesSet.insert(portName).second) {
2946 emitOpError() <<
"has non-unique port name " << portName;
2954 auto elt = getPortNamed(portName);
2956 emitOpError() <<
"could not get port with name " << portName;
2959 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2962 if (portKind == MemOp::PortKind::Debug &&
2963 !type_isa<RefType>(getResult(i).getType()))
2964 return emitOpError() <<
"has an invalid type on port " << portName
2965 <<
" (expected Read/Write/ReadWrite/Debug)";
2966 if (type_isa<RefType>(firrtlType) && e == 1)
2967 return emitOpError()
2968 <<
"cannot have only one port of debug type. Debug port can only "
2969 "exist alongside other read/write/read-write port";
2974 if (portKind == MemOp::PortKind::Debug) {
2975 auto resType = type_cast<RefType>(getResult(i).getType());
2976 if (!(resType && type_isa<FVectorType>(resType.getType())))
2977 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2978 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2980 auto dataTypeOption = portBundleType.getElement(
"data");
2981 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2982 dataTypeOption = portBundleType.getElement(
"wdata");
2983 if (!dataTypeOption) {
2984 emitOpError() <<
"has no data field on port " << portName
2985 <<
" (expected to see \"data\" for a read or write "
2986 "port or \"rdata\" for a read/write port)";
2989 dataType = dataTypeOption->type;
2991 if (portKind == MemOp::PortKind::Read) {
2998 emitOpError() <<
"has non-passive data type on port " << portName
2999 <<
" (memory types must be passive)";
3004 if (dataType.containsAnalog()) {
3005 emitOpError() <<
"has a data type that contains an analog type on port "
3007 <<
" (memory types cannot contain analog types)";
3015 getTypeForPort(getDepth(), dataType, portKind,
3016 dataType.isGround() ? getMaskBits() : 0);
3019 auto originalType = getResult(i).getType();
3020 if (originalType != expectedType) {
3021 StringRef portKindName;
3023 case MemOp::PortKind::Read:
3024 portKindName =
"read";
3026 case MemOp::PortKind::Write:
3027 portKindName =
"write";
3029 case MemOp::PortKind::ReadWrite:
3030 portKindName =
"readwrite";
3032 case MemOp::PortKind::Debug:
3033 portKindName =
"dbg";
3036 emitOpError() <<
"has an invalid type for port " << portName
3037 <<
" of determined kind \"" << portKindName
3038 <<
"\" (expected " << expectedType <<
", but got "
3039 << originalType <<
")";
3045 if (oldDataType && oldDataType != dataType) {
3046 emitOpError() <<
"port " << getPortName(i)
3047 <<
" has a different type than port " << getPortName(i - 1)
3048 <<
" (expected " << oldDataType <<
", but got " << dataType
3053 oldDataType = dataType;
3056 auto maskWidth = getMaskBits();
3058 auto dataWidth = getDataType().getBitWidthOrSentinel();
3059 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3060 return emitOpError(
"the mask width cannot be greater than "
3063 if (getPortAnnotations().size() != getNumResults())
3064 return emitOpError(
"the number of result annotations should be "
3065 "equal to the number of results");
3071 return std::max(1U, llvm::Log2_64_Ceil(depth));
3077 PortKind portKind,
size_t maskBits) {
3079 auto *context = dataType.getContext();
3080 if (portKind == PortKind::Debug)
3081 return RefType::get(FVectorType::get(dataType, depth));
3087 maskType = UIntType::get(context, maskBits);
3089 auto getId = [&](StringRef name) -> StringAttr {
3090 return StringAttr::get(context, name);
3093 SmallVector<BundleType::BundleElement, 7> portFields;
3097 portFields.push_back({getId(
"addr"),
false, addressType});
3098 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3099 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3102 case PortKind::Read:
3103 portFields.push_back({getId(
"data"),
true, dataType});
3106 case PortKind::Write:
3107 portFields.push_back({getId(
"data"),
false, dataType});
3108 portFields.push_back({getId(
"mask"),
false, maskType});
3111 case PortKind::ReadWrite:
3112 portFields.push_back({getId(
"rdata"),
true, dataType});
3113 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3114 portFields.push_back({getId(
"wdata"),
false, dataType});
3115 portFields.push_back({getId(
"wmask"),
false, maskType});
3118 llvm::report_fatal_error(
"memory port kind not handled");
3122 return BundleType::get(context, portFields);
3126SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3127 SmallVector<MemOp::NamedPort> result;
3129 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3131 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3138MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3140 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3144MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3146 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3150size_t MemOp::getMaskBits() {
3152 for (
auto res : getResults()) {
3153 if (type_isa<RefType>(res.getType()))
3155 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3162 if (t.name.getValue().contains(
"mask"))
3165 if (type_isa<UIntType>(mType))
3175 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3177 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3178 return type_cast<FVectorType>(refType.getType()).getElementType();
3179 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3181 StringRef dataFieldName =
"data";
3183 dataFieldName =
"rdata";
3185 return type_cast<BundleType>(firstPortType.getPassiveType())
3186 .getElementType(dataFieldName);
3189StringAttr MemOp::getPortName(
size_t resultNo) {
3190 return cast<StringAttr>(getPortNames()[resultNo]);
3194 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3197Value MemOp::getPortNamed(StringAttr name) {
3198 auto namesArray = getPortNames();
3199 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3200 if (namesArray[i] == name) {
3201 assert(i < getNumResults() &&
" names array out of sync with results");
3202 return getResult(i);
3211 size_t numReadPorts = 0;
3212 size_t numWritePorts = 0;
3213 size_t numReadWritePorts = 0;
3215 SmallVector<int32_t> writeClockIDs;
3217 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3218 auto portKind = op.getPortKind(i);
3219 if (portKind == MemOp::PortKind::Read)
3221 else if (portKind == MemOp::PortKind::Write) {
3222 for (
auto *a : op.getResult(i).getUsers()) {
3223 auto subfield = dyn_cast<SubfieldOp>(a);
3224 if (!subfield || subfield.getFieldIndex() != 2)
3226 auto clockPort = a->getResult(0);
3227 for (
auto *b : clockPort.getUsers()) {
3228 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3229 if (
connect.getDest() == clockPort) {
3232 connect.getSrc(),
true,
true,
true),
3234 if (result.second) {
3235 writeClockIDs.push_back(numWritePorts);
3237 writeClockIDs.push_back(result.first->second);
3246 ++numReadWritePorts;
3253 op.emitError(
"'firrtl.mem' should have simple type and known width");
3254 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3256 if (op->hasAttr(
"modName"))
3257 modName = op->getAttrOfType<StringAttr>(
"modName");
3259 SmallString<8> clocks;
3260 for (
auto a : writeClockIDs)
3261 clocks.
append(Twine((char)(a +
'a')).str());
3262 SmallString<32> initStr;
3267 for (
auto c : init.getFilename().getValue())
3268 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3269 (c >=
'0' && c <=
'9'))
3270 initStr.push_back(c);
3271 initStr.push_back(
'_');
3272 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3273 initStr.push_back(
'_');
3274 initStr.push_back(init.getIsInline() ?
't' :
'f');
3276 modName = StringAttr::get(
3279 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3280 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3281 numReadWritePorts, (
size_t)width, op.getDepth(),
3282 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3283 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3284 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3286 return {numReadPorts,
3291 op.getReadLatency(),
3292 op.getWriteLatency(),
3294 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3295 seq::WUW::PortOrder,
3298 op.getMaskBits() > 1,
3304void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3309 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3310 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3314std::optional<size_t> MemOp::getTargetResultIndex() {
3316 return std::nullopt;
3324 OpAsmSetValueNameFn setNameFn) {
3327 setNameFn(op.getDataRaw(), name);
3328 if (op.isForceable())
3329 setNameFn(op.getDataRef(), (name +
"_ref").str());
3332void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3336LogicalResult NodeOp::inferReturnTypes(
3337 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3338 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3339 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3340 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3341 if (operands.empty())
3343 Adaptor adaptor(operands, attributes, properties, regions);
3344 inferredReturnTypes.push_back(adaptor.getInput().getType());
3345 if (adaptor.getForceable()) {
3347 true, adaptor.getInput().getType());
3348 if (!forceableType) {
3350 ::mlir::emitError(*location,
"cannot force a node of type ")
3351 << operands[0].getType();
3354 inferredReturnTypes.push_back(forceableType);
3359std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3361void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3365std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3367SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3368RegOp::computeDataFlow() {
3373LogicalResult RegResetOp::verify() {
3374 auto reset = getResetValue();
3381 return emitError(
"type mismatch between register ")
3382 << regType <<
" and reset value " << resetType;
3387std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3389void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3398FormalOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
3400 auto referencedModule = symbolTable.lookupNearestSymbolFrom<FModuleOp>(
3401 *
this, getModuleNameAttr());
3402 if (!referencedModule)
3403 return (*this)->emitOpError(
"invalid symbol reference");
3412void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3416SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3417RegResetOp::computeDataFlow() {
3422std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3424LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3425 auto refType = type_dyn_cast<RefType>(getType(0));
3430 refType, getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3431 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3438LogicalResult ContractOp::verify() {
3439 if (getBody().getArgumentTypes() != getInputs().getType())
3440 return emitOpError(
"result types and region argument types must match");
3448void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3450 build(builder, state, klass.getInstanceType(),
3451 StringAttr::get(builder.getContext(), name));
3454LogicalResult ObjectOp::verify() {
return success(); }
3456LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3457 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3458 auto classType = getType();
3459 auto className = classType.getNameAttr();
3462 auto classOp = dyn_cast_or_null<ClassLike>(
3463 symbolTable.lookupSymbolIn(circuitOp, className));
3465 return emitOpError() <<
"references unknown class " << className;
3468 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3474StringAttr ObjectOp::getClassNameAttr() {
3475 return getType().getNameAttr().getAttr();
3478StringRef ObjectOp::getClassName() {
return getType().getName(); }
3480ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3481 auto symRef = getType().getNameAttr();
3482 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3485Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3486 return getReferencedClass(symtbl);
3489StringRef ObjectOp::getInstanceName() {
return getName(); }
3491StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3493StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3495StringAttr ObjectOp::getReferencedModuleNameAttr() {
3496 return getClassNameAttr();
3499void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3500 setNameFn(getResult(),
getName());
3507LogicalResult AttachOp::verify() {
3509 std::optional<int32_t> commonWidth;
3510 for (
auto operand : getOperands()) {
3511 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3515 commonWidth = thisWidth;
3518 if (commonWidth != thisWidth)
3519 return emitOpError(
"is inavlid as not all known operand widths match");
3526 Value dst = connect->getOperand(0);
3527 Value src = connect->getOperand(1);
3536 if (isa<PropertyType>(src.getType()) ||
3540 auto diag = emitError(connect->getLoc());
3541 diag <<
"connect has invalid flow: the source expression ";
3543 diag <<
"\"" << srcName <<
"\" ";
3544 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3545 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3553 auto diag = emitError(connect->getLoc());
3554 diag <<
"connect has invalid flow: the destination expression ";
3556 diag <<
"\"" << dstName <<
"\" ";
3557 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3558 return diag.attachNote(dstRef.getLoc())
3559 <<
"the destination was defined here";
3568 bool outerTypeIsConst =
false) {
3569 auto typeIsConst = outerTypeIsConst || type.
isConst();
3574 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3575 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3576 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3580 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3592 auto dest = connect.getDest();
3593 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3594 auto src = connect.getSrc();
3595 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3596 if (!destType || !srcType)
3599 auto destRefinedType = destType;
3600 auto srcRefinedType = srcType;
3605 auto findFieldDeclarationRefiningFieldType =
3607 while (
auto *definingOp = value.getDefiningOp()) {
3608 bool shouldContinue =
true;
3609 TypeSwitch<Operation *>(definingOp)
3610 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3611 .Case<SubaccessOp>([&](SubaccessOp op) {
3615 .getElementTypePreservingConst()
3617 originalFieldType = originalFieldType.getConstType(
true);
3618 value = op.getInput();
3620 .Default([&](Operation *) { shouldContinue =
false; });
3621 if (!shouldContinue)
3627 auto destDeclaration =
3628 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3629 auto srcDeclaration =
3630 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3632 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3633 Value declaration) -> LogicalResult {
3634 auto *declarationBlock = declaration.getParentBlock();
3635 auto *block = connect->getBlock();
3636 while (block && block != declarationBlock) {
3637 auto *parentOp = block->getParentOp();
3639 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3640 whenOp && !whenOp.getCondition().getType().isConst()) {
3642 return connect.emitOpError()
3643 <<
"assignment to 'const' type " << type
3644 <<
" is dependent on a non-'const' condition";
3645 return connect->emitOpError()
3646 <<
"assignment to nested 'const' member of type " << type
3647 <<
" is dependent on a non-'const' condition";
3650 block = parentOp->getBlock();
3655 auto emitSubaccessError = [&] {
3656 return connect.emitError(
3657 "assignment to non-'const' subaccess of 'const' type is disallowed");
3663 if (destType != destRefinedType)
3664 return emitSubaccessError();
3666 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3671 if (srcRefinedType.containsConst() &&
3674 if (srcType != srcRefinedType)
3675 return emitSubaccessError();
3676 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3683LogicalResult ConnectOp::verify() {
3684 auto dstType = getDest().getType();
3685 auto srcType = getSrc().getType();
3686 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3687 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3688 if (!dstBaseType || !srcBaseType) {
3689 if (dstType != srcType)
3690 return emitError(
"may not connect different non-base types");
3693 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3694 return emitError(
"analog types may not be connected");
3698 return emitError(
"type mismatch between destination ")
3699 << dstBaseType <<
" and source " << srcBaseType;
3704 return emitError(
"destination ")
3705 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3718LogicalResult MatchingConnectOp::verify() {
3719 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3720 auto baseType = type_cast<FIRRTLBaseType>(type);
3723 if (baseType && baseType.containsAnalog())
3724 return emitError(
"analog types may not be connected");
3729 "`SameAnonTypeOperands` trait should have already rejected "
3730 "structurally non-equivalent types");
3743LogicalResult RefDefineOp::verify() {
3753 for (
auto *user : getDest().getUsers()) {
3754 if (
auto conn = dyn_cast<FConnectLike>(user);
3755 conn && conn.getDest() == getDest() && conn != *
this)
3756 return emitError(
"destination reference cannot be reused by multiple "
3757 "operations, it can only capture a unique dataflow");
3761 if (
auto *op = getDest().getDefiningOp()) {
3763 if (isa<RefSubOp>(op))
3765 "destination reference cannot be a sub-element of a reference");
3766 if (isa<RefCastOp>(op))
3768 "destination reference cannot be a cast of another reference");
3776 SmallVector<SymbolRefAttr> missingLayers;
3778 auto diag = emitOpError(
"has more layer requirements than destination");
3779 auto ¬e = diag.attachNote();
3780 note <<
"additional layers required: ";
3781 interleaveComma(missingLayers, note);
3788LogicalResult PropAssignOp::verify() {
3794 for (
auto *user : getDest().getUsers()) {
3795 if (
auto conn = dyn_cast<FConnectLike>(user);
3796 conn && conn.getDest() == getDest() && conn != *
this)
3797 return emitError(
"destination property cannot be reused by multiple "
3798 "operations, it can only capture a unique dataflow");
3804void WhenOp::createElseRegion() {
3805 assert(!hasElseRegion() &&
"already has an else region");
3806 getElseRegion().push_back(
new Block());
3809void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
3810 bool withElseRegion, std::function<
void()> thenCtor,
3811 std::function<
void()> elseCtor) {
3812 OpBuilder::InsertionGuard guard(builder);
3813 result.addOperands(condition);
3816 builder.createBlock(result.addRegion());
3821 Region *elseRegion = result.addRegion();
3822 if (withElseRegion) {
3823 builder.createBlock(elseRegion);
3833LogicalResult MatchOp::verify() {
3834 FEnumType type = getInput().getType();
3837 auto numCases = getTags().size();
3838 auto numRegions = getNumRegions();
3839 if (numRegions != numCases)
3840 return emitOpError(
"expected ")
3841 << numRegions <<
" tags but got " << numCases;
3843 auto numTags = type.getNumElements();
3845 SmallDenseSet<int64_t> seen;
3846 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
3847 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3850 if (region.getNumArguments() != 1)
3851 return emitOpError(
"region should have exactly one argument");
3854 if (tagIndex >= numTags)
3855 return emitOpError(
"the tag index ")
3856 << tagIndex <<
" is out of the range of valid tags in " << type;
3859 auto [it, inserted] = seen.insert(tagIndex);
3861 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3862 <<
" is matched more than once";
3865 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3866 auto regionType = region.getArgument(0).getType();
3867 if (regionType != expectedType)
3868 return emitOpError(
"region type ")
3869 << regionType <<
" does not match the expected type "
3874 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3875 if (!seen.contains(i))
3876 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3881void MatchOp::print(OpAsmPrinter &p) {
3882 auto input = getInput();
3883 FEnumType type = input.getType();
3884 auto regions = getRegions();
3885 p <<
" " << input <<
" : " << type;
3886 SmallVector<StringRef> elided = {
"tags"};
3887 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3890 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
3893 p.printKeywordOrString(
3894 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3896 p.printRegionArgument(region.front().getArgument(0), {},
3899 p.printRegion(region,
false);
3906ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3907 auto *context = parser.getContext();
3908 auto &properties = result.getOrAddProperties<Properties>();
3909 OpAsmParser::UnresolvedOperand input;
3910 if (parser.parseOperand(input) || parser.parseColon())
3913 auto loc = parser.getCurrentLocation();
3915 if (parser.parseType(type))
3917 auto enumType = type_dyn_cast<FEnumType>(type);
3919 return parser.emitError(loc,
"expected enumeration type but got") << type;
3921 if (parser.resolveOperand(input, type, result.operands) ||
3922 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
3923 parser.parseLBrace())
3926 auto i32Type = IntegerType::get(context, 32);
3927 SmallVector<Attribute> tags;
3930 if (failed(parser.parseOptionalKeyword(
"case")))
3934 auto nameLoc = parser.getCurrentLocation();
3936 OpAsmParser::Argument arg;
3937 auto *region = result.addRegion();
3938 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
3939 parser.parseArgument(arg) || parser.parseRParen())
3943 auto index = enumType.getElementIndex(name);
3945 return parser.emitError(nameLoc,
"the tag \"")
3946 << name <<
"\" is not a member of the enumeration " << enumType;
3947 tags.push_back(IntegerAttr::get(i32Type, *index));
3950 arg.type = enumType.getElementTypePreservingConst(*index);
3951 if (parser.parseRegion(*region, arg))
3954 properties.setTags(ArrayAttr::get(context, tags));
3956 return parser.parseRBrace();
3959void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
3961 MutableArrayRef<std::unique_ptr<Region>> regions) {
3962 auto &properties = result.getOrAddProperties<Properties>();
3963 result.addOperands(input);
3964 properties.setTags(tags);
3965 result.addRegions(regions);
3974 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
3975 bool visitInvalidExpr(Operation *op) {
return false; }
3976 bool visitUnhandledExpr(Operation *op) {
return true; }
3982void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3985 if (
auto ty = type_dyn_cast<IntType>(getType())) {
3986 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
3987 auto width = ty.getWidthOrSentinel();
3991 name = (Twine(base) + Twine(width)).str();
3992 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
3993 auto width = ty.getWidthOrSentinel();
3995 name =
"invalid_analog";
3997 name = (
"invalid_analog" + Twine(width)).str();
3998 }
else if (type_isa<AsyncResetType>(getType()))
3999 name =
"invalid_asyncreset";
4000 else if (type_isa<ResetType>(getType()))
4001 name =
"invalid_reset";
4002 else if (type_isa<ClockType>(getType()))
4003 name =
"invalid_clock";
4007 setNameFn(getResult(), name);
4010void ConstantOp::print(OpAsmPrinter &p) {
4012 p.printAttributeWithoutType(getValueAttr());
4014 p.printType(getType());
4015 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4018ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4019 auto &properties = result.getOrAddProperties<Properties>();
4022 auto loc = parser.getCurrentLocation();
4023 auto valueResult = parser.parseOptionalInteger(value);
4024 if (!valueResult.has_value())
4025 return parser.emitError(loc,
"expected integer value");
4029 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4030 parser.parseOptionalAttrDict(result.attributes))
4032 result.addTypes(resultType);
4038 if (width > value.getBitWidth()) {
4042 value = value.sext(width);
4043 }
else if (width < value.getBitWidth()) {
4046 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4047 : value.getActiveBits();
4048 if (width < neededBits)
4049 return parser.emitError(loc,
"constant out of range for result type ")
4051 value = value.trunc(width);
4055 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4057 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4058 properties.setValue(valueAttr);
4062LogicalResult ConstantOp::verify() {
4066 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4068 "firrtl.constant attribute bitwidth doesn't match return type");
4071 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4072 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4073 return emitError(
"firrtl.constant attribute has wrong sign");
4080void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4081 const APInt &value) {
4084 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4085 "incorrect attribute bitwidth for firrtl.constant");
4088 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4089 return build(builder, result, type, attr);
4094void ConstantOp::build(OpBuilder &builder, OperationState &result,
4095 const APSInt &value) {
4096 auto attr = IntegerAttr::get(builder.getContext(), value);
4098 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4099 return build(builder, result, type, attr);
4102void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4109 SmallString<32> specialNameBuffer;
4110 llvm::raw_svector_ostream specialName(specialNameBuffer);
4112 getValue().print(specialName, intTy.
isSigned());
4114 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4117 specialName << width;
4118 setNameFn(getResult(), specialName.str());
4121void SpecialConstantOp::print(OpAsmPrinter &p) {
4124 p << static_cast<unsigned>(getValue());
4126 p.printType(getType());
4127 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4130ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4131 OperationState &result) {
4132 auto &properties = result.getOrAddProperties<Properties>();
4136 auto loc = parser.getCurrentLocation();
4137 auto valueResult = parser.parseOptionalInteger(value);
4138 if (!valueResult.has_value())
4139 return parser.emitError(loc,
"expected integer value");
4142 if (value != 0 && value != 1)
4143 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4147 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4148 parser.parseOptionalAttrDict(result.attributes))
4150 result.addTypes(resultType);
4153 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4154 properties.setValue(valueAttr);
4158void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4159 SmallString<32> specialNameBuffer;
4160 llvm::raw_svector_ostream specialName(specialNameBuffer);
4162 specialName << static_cast<unsigned>(getValue());
4163 auto type = getType();
4164 if (type_isa<ClockType>(type)) {
4165 specialName <<
"_clock";
4166 }
else if (type_isa<ResetType>(type)) {
4167 specialName <<
"_reset";
4168 }
else if (type_isa<AsyncResetType>(type)) {
4169 specialName <<
"_asyncreset";
4171 setNameFn(getResult(), specialName.str());
4178 if (type.isGround()) {
4179 if (!isa<IntegerAttr>(attr)) {
4180 op->emitOpError(
"Ground type is not an integer attribute");
4185 auto attrlist = dyn_cast<ArrayAttr>(attr);
4187 op->emitOpError(
"expected array attribute for aggregate constant");
4190 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4191 if (array.getNumElements() != attrlist.size()) {
4192 op->emitOpError(
"array attribute (")
4193 << attrlist.size() <<
") has wrong size for vector constant ("
4194 << array.getNumElements() <<
")";
4197 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4201 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4202 if (bundle.getNumElements() != attrlist.size()) {
4203 op->emitOpError(
"array attribute (")
4204 << attrlist.size() <<
") has wrong size for bundle constant ("
4205 << bundle.getNumElements() <<
")";
4208 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4209 if (bundle.getElement(i).isFlip) {
4210 op->emitOpError(
"Cannot have constant bundle type with flip");
4218 op->emitOpError(
"Unknown aggregate type");
4222LogicalResult AggregateConstantOp::verify() {
4228Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4230 Attribute value = getFields();
4231 while (fieldID != 0) {
4232 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4233 auto index = bundle.getIndexForFieldID(fieldID);
4234 fieldID -= bundle.getFieldID(index);
4235 type = bundle.getElementType(index);
4236 value = cast<ArrayAttr>(value)[index];
4238 auto vector = type_cast<FVectorType>(type);
4239 auto index = vector.getIndexForFieldID(fieldID);
4240 fieldID -= vector.getFieldID(index);
4241 type = vector.getElementType();
4242 value = cast<ArrayAttr>(value)[index];
4248void FIntegerConstantOp::print(OpAsmPrinter &p) {
4250 p.printAttributeWithoutType(getValueAttr());
4251 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4254ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4255 OperationState &result) {
4256 auto *context = parser.getContext();
4257 auto &properties = result.getOrAddProperties<Properties>();
4259 if (parser.parseInteger(value) ||
4260 parser.parseOptionalAttrDict(result.attributes))
4262 result.addTypes(FIntegerType::get(context));
4264 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4265 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4266 properties.setValue(valueAttr);
4270ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4271 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4274 if (parser.parseOperandList(operands) ||
4275 parser.parseOptionalAttrDict(result.attributes) ||
4276 parser.parseColonType(type))
4278 result.addTypes(type);
4280 return parser.resolveOperands(operands, type.getElementType(),
4284void ListCreateOp::print(OpAsmPrinter &p) {
4286 p.printOperands(getElements());
4287 p.printOptionalAttrDict((*this)->getAttrs());
4288 p <<
" : " << getType();
4291LogicalResult ListCreateOp::verify() {
4292 if (getElements().
empty())
4295 auto elementType = getElements().front().getType();
4296 auto listElementType = getType().getElementType();
4298 return emitOpError(
"has elements of type ")
4299 <<
elementType <<
" instead of " << listElementType;
4304LogicalResult BundleCreateOp::verify() {
4305 BundleType resultType = getType();
4306 if (resultType.getNumElements() != getFields().size())
4307 return emitOpError(
"number of fields doesn't match type");
4308 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4310 resultType.getElementTypePreservingConst(i),
4311 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4312 return emitOpError(
"type of element doesn't match bundle for field ")
4313 << resultType.getElement(i).name;
4318LogicalResult VectorCreateOp::verify() {
4319 FVectorType resultType = getType();
4320 if (resultType.getNumElements() != getFields().size())
4321 return emitOpError(
"number of fields doesn't match type");
4322 auto elemTy = resultType.getElementTypePreservingConst();
4323 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4325 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4326 return emitOpError(
"type of element doesn't match vector element");
4335LogicalResult FEnumCreateOp::verify() {
4336 FEnumType resultType = getResult().getType();
4337 auto elementIndex = resultType.getElementIndex(
getFieldName());
4339 return emitOpError(
"label ")
4340 <<
getFieldName() <<
" is not a member of the enumeration type "
4343 resultType.getElementTypePreservingConst(*elementIndex),
4344 getInput().getType()))
4345 return emitOpError(
"type of element doesn't match enum element");
4349void FEnumCreateOp::print(OpAsmPrinter &printer) {
4352 printer <<
'(' << getInput() <<
')';
4353 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4354 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4356 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4357 ArrayRef<Type>{getResult().getType()});
4360ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4361 auto *context = parser.getContext();
4362 auto &properties = result.getOrAddProperties<Properties>();
4364 OpAsmParser::UnresolvedOperand input;
4365 std::string fieldName;
4366 mlir::FunctionType functionType;
4367 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4368 parser.parseOperand(input) || parser.parseRParen() ||
4369 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4370 parser.parseType(functionType))
4373 if (functionType.getNumInputs() != 1)
4374 return parser.emitError(parser.getNameLoc(),
"single input type required");
4375 if (functionType.getNumResults() != 1)
4376 return parser.emitError(parser.getNameLoc(),
"single result type required");
4378 auto inputType = functionType.getInput(0);
4379 if (parser.resolveOperand(input, inputType, result.operands))
4382 auto outputType = functionType.getResult(0);
4383 auto enumType = type_dyn_cast<FEnumType>(outputType);
4385 return parser.emitError(parser.getNameLoc(),
4386 "output must be enum type, got ")
4388 auto fieldIndex = enumType.getElementIndex(fieldName);
4390 return parser.emitError(parser.getNameLoc(),
4391 "unknown field " + fieldName +
" in enum type ")
4394 properties.setFieldIndex(
4395 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4397 result.addTypes(enumType);
4406LogicalResult IsTagOp::verify() {
4407 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4408 return emitOpError(
"element index is greater than the number of fields in "
4413void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4414 printer <<
' ' << getInput() <<
' ';
4416 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4417 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4418 printer <<
" : " << getInput().getType();
4421ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4422 auto *context = parser.getContext();
4423 auto &properties = result.getOrAddProperties<Properties>();
4425 OpAsmParser::UnresolvedOperand input;
4426 std::string fieldName;
4428 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4429 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4430 parser.parseType(inputType))
4433 if (parser.resolveOperand(input, inputType, result.operands))
4436 auto enumType = type_dyn_cast<FEnumType>(inputType);
4438 return parser.emitError(parser.getNameLoc(),
4439 "input must be enum type, got ")
4441 auto fieldIndex = enumType.getElementIndex(fieldName);
4443 return parser.emitError(parser.getNameLoc(),
4444 "unknown field " + fieldName +
" in enum type ")
4447 properties.setFieldIndex(
4448 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4450 result.addTypes(UIntType::get(context, 1,
false));
4455FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4456 OpaqueProperties properties,
4457 mlir::RegionRange regions,
4458 std::optional<Location> loc) {
4459 Adaptor adaptor(operands, attrs, properties, regions);
4460 return UIntType::get(attrs.getContext(), 1,
4461 isConst(adaptor.getInput().getType()));
4464template <
typename OpTy>
4466 auto *context = parser.getContext();
4468 OpAsmParser::UnresolvedOperand input;
4469 std::string fieldName;
4471 if (parser.parseOperand(input) || parser.parseLSquare() ||
4472 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4473 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4474 parser.parseType(inputType))
4477 if (parser.resolveOperand(input, inputType, result.operands))
4480 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4482 return parser.emitError(parser.getNameLoc(),
4483 "input must be bundle type, got ")
4485 auto fieldIndex = bundleType.getElementIndex(fieldName);
4487 return parser.emitError(parser.getNameLoc(),
4488 "unknown field " + fieldName +
" in bundle type ")
4491 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4492 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4494 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4497 result.addTypes(type);
4502ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4503 auto *context = parser.getContext();
4505 OpAsmParser::UnresolvedOperand input;
4506 std::string fieldName;
4508 if (parser.parseOperand(input) || parser.parseLSquare() ||
4509 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4510 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4511 parser.parseType(inputType))
4514 if (parser.resolveOperand(input, inputType, result.operands))
4517 auto enumType = type_dyn_cast<FEnumType>(inputType);
4519 return parser.emitError(parser.getNameLoc(),
4520 "input must be enum type, got ")
4522 auto fieldIndex = enumType.getElementIndex(fieldName);
4524 return parser.emitError(parser.getNameLoc(),
4525 "unknown field " + fieldName +
" in enum type ")
4528 result.getOrAddProperties<Properties>().setFieldIndex(
4529 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4531 SmallVector<Type> inferredReturnTypes;
4532 if (failed(SubtagOp::inferReturnTypes(
4533 context, result.location, result.operands,
4534 result.attributes.getDictionary(context), result.getRawProperties(),
4535 result.regions, inferredReturnTypes)))
4537 result.addTypes(inferredReturnTypes);
4542ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4543 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4545ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4546 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4549template <
typename OpTy>
4551 printer <<
' ' << op.getInput() <<
'[';
4552 printer.printKeywordOrString(op.getFieldName());
4554 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4555 elidedAttrs.push_back(
"fieldIndex");
4556 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4557 printer <<
" : " << op.getInput().getType();
4559void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4560 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4562void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4563 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4566void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4567 printer <<
' ' << getInput() <<
'[';
4570 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4571 elidedAttrs.push_back(
"fieldIndex");
4572 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4573 printer <<
" : " << getInput().getType();
4576template <
typename OpTy>
4578 if (op.getFieldIndex() >=
4579 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4581 return op.emitOpError(
"subfield element index is greater than the number "
4582 "of fields in the bundle type");
4585LogicalResult SubfieldOp::verify() {
4586 return verifySubfieldLike<SubfieldOp>(*
this);
4588LogicalResult OpenSubfieldOp::verify() {
4589 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4592LogicalResult SubtagOp::verify() {
4593 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4594 return emitOpError(
"subfield element index is greater than the number "
4595 "of fields in the bundle type");
4605 SmallVector<Operation *, 8> worklist({op});
4609 bool constant =
true;
4615 while (constant && !(worklist.empty()))
4616 TypeSwitch<Operation *>(worklist.pop_back_val())
4617 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4618 if (
auto definingOp = op.getInput().getDefiningOp())
4619 worklist.push_back(definingOp);
4622 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4623 for (
auto &use : op.getResult().getUses())
4624 worklist.push_back(use.getOwner());
4626 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4627 .Default([&](
auto) { constant =
false; });
4636 if (
auto *op = value.getDefiningOp())
4641LogicalResult ConstCastOp::verify() {
4643 return emitOpError() << getInput().getType()
4644 <<
" is not 'const'-castable to "
4645 << getResult().getType();
4649FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4650 std::optional<Location> loc) {
4651 auto inType = type_cast<BundleType>(type);
4653 if (fieldIndex >= inType.getNumElements())
4655 "subfield element index is greater than the "
4656 "number of fields in the bundle type");
4660 return inType.getElementTypePreservingConst(fieldIndex);
4663FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4664 std::optional<Location> loc) {
4665 auto inType = type_cast<OpenBundleType>(type);
4667 if (fieldIndex >= inType.getNumElements())
4669 "subfield element index is greater than the "
4670 "number of fields in the bundle type");
4674 return inType.getElementTypePreservingConst(fieldIndex);
4677bool SubfieldOp::isFieldFlipped() {
4678 BundleType bundle = getInput().getType();
4679 return bundle.getElement(getFieldIndex()).isFlip;
4681bool OpenSubfieldOp::isFieldFlipped() {
4682 auto bundle = getInput().getType();
4683 return bundle.getElement(getFieldIndex()).isFlip;
4686FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4687 std::optional<Location> loc) {
4688 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
4689 if (fieldIndex < vectorType.getNumElements())
4690 return vectorType.getElementTypePreservingConst();
4692 "' in vector type ", type);
4697FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4698 std::optional<Location> loc) {
4699 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
4700 if (fieldIndex < vectorType.getNumElements())
4701 return vectorType.getElementTypePreservingConst();
4703 "' in vector type ", type);
4709FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4710 OpaqueProperties properties,
4711 mlir::RegionRange regions,
4712 std::optional<Location> loc) {
4713 Adaptor adaptor(operands, attrs, properties, regions);
4714 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4715 auto fieldIndex = adaptor.getFieldIndex();
4717 if (fieldIndex >= inType.getNumElements())
4719 "subtag element index is greater than the "
4720 "number of fields in the enum type");
4724 auto elementType = inType.getElement(fieldIndex).type;
4728FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
4729 std::optional<Location> loc) {
4730 if (!type_isa<UIntType>(indexType))
4734 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4736 return vectorType.getElementTypePreservingConst();
4737 return vectorType.getElementType().getAllConstDroppedType();
4744FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4745 DictionaryAttr attrs,
4746 OpaqueProperties properties,
4747 mlir::RegionRange regions,
4748 std::optional<Location> loc) {
4749 Adaptor adaptor(operands, attrs, properties, regions);
4750 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4751 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4752 return UIntType::get(inType.getContext(), i);
4755ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4756 OpAsmParser::UnresolvedOperand index;
4757 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
4758 Type indexType, elemType;
4760 if (parser.parseOperand(index) || parser.parseComma() ||
4761 parser.parseOperandList(inputs) ||
4762 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4763 parser.parseType(indexType) || parser.parseComma() ||
4764 parser.parseType(elemType))
4767 if (parser.resolveOperand(index, indexType, result.operands))
4770 result.addTypes(elemType);
4772 return parser.resolveOperands(inputs, elemType, result.operands);
4775void MultibitMuxOp::print(OpAsmPrinter &p) {
4776 p <<
" " << getIndex() <<
", ";
4777 p.printOperands(getInputs());
4778 p.printOptionalAttrDict((*this)->getAttrs());
4779 p <<
" : " << getIndex().getType() <<
", " << getType();
4782FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4783 DictionaryAttr attrs,
4784 OpaqueProperties properties,
4785 mlir::RegionRange regions,
4786 std::optional<Location> loc) {
4787 if (operands.size() < 2)
4791 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4792 return operands[1].getType() == op.getType();
4796 return type_cast<FIRRTLType>(operands[1].getType());
4803LogicalResult ObjectSubfieldOp::inferReturnTypes(
4804 MLIRContext *context, std::optional<mlir::Location> location,
4805 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4806 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4808 inferReturnType(operands, attributes, properties, regions, location);
4811 inferredReturnTypes.push_back(type);
4815Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
4816 std::optional<Location> loc) {
4817 auto classType = dyn_cast<ClassType>(inType);
4821 if (classType.getNumElements() <= fieldIndex)
4823 "number of fields in the object");
4824 return classType.getElement(fieldIndex).type;
4827void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4828 auto input = getInput();
4829 auto classType = input.getType();
4830 p <<
' ' << input <<
"[";
4831 p.printKeywordOrString(classType.getElement(getIndex()).name);
4833 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4834 p <<
" : " << classType;
4837ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4838 OperationState &result) {
4839 auto *context = parser.getContext();
4841 OpAsmParser::UnresolvedOperand input;
4842 std::string fieldName;
4843 ClassType inputType;
4844 if (parser.parseOperand(input) || parser.parseLSquare() ||
4845 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4846 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4847 parser.parseType(inputType) ||
4848 parser.resolveOperand(input, inputType, result.operands))
4851 auto index = inputType.getElementIndex(fieldName);
4853 return parser.emitError(parser.getNameLoc(),
4854 "unknown field " + fieldName +
" in class type ")
4856 result.getOrAddProperties<Properties>().setIndex(
4857 IntegerAttr::get(IntegerType::get(context, 32), *index));
4859 SmallVector<Type> inferredReturnTypes;
4860 if (failed(inferReturnTypes(context, result.location, result.operands,
4861 result.attributes.getDictionary(context),
4862 result.getRawProperties(), result.regions,
4863 inferredReturnTypes)))
4865 result.addTypes(inferredReturnTypes);
4882 int32_t &rhsWidth,
bool &isConstResult,
4883 std::optional<Location> loc) {
4885 auto lhsi = type_dyn_cast<IntType>(lhs);
4886 auto rhsi = type_dyn_cast<IntType>(rhs);
4887 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4890 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4892 else if (!lhsi && rhsi)
4893 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4895 else if (!lhsi && !rhsi)
4896 mlir::emitError(*loc,
"operands must be integer types, not ")
4897 << lhs <<
" and " << rhs;
4899 mlir::emitError(*loc,
"operand signedness must match");
4904 lhsWidth = lhsi.getWidthOrSentinel();
4905 rhsWidth = rhsi.getWidthOrSentinel();
4906 isConstResult = lhsi.isConst() && rhsi.isConst();
4911 assert(op->getNumOperands() == 2 &&
4912 "SameOperandsIntTypeKind on non-binary op");
4913 int32_t lhsWidth, rhsWidth;
4916 op->getOperand(1).getType(), lhsWidth,
4917 rhsWidth, isConstResult, op->getLoc()));
4921 std::optional<Location> loc) {
4922 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4923 bool isConstResult =
false;
4927 if (lhsWidth != -1 && rhsWidth != -1)
4928 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
4929 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4934 std::optional<Location> loc) {
4935 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4936 bool isConstResult =
false;
4940 if (lhsWidth != -1 && rhsWidth != -1)
4941 resultWidth = lhsWidth + rhsWidth;
4943 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4948 std::optional<Location> loc) {
4949 int32_t lhsWidth, rhsWidth;
4950 bool isConstResult =
false;
4955 if (type_isa<UIntType>(lhs))
4956 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
4959 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
4960 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
4964 std::optional<Location> loc) {
4965 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4966 bool isConstResult =
false;
4970 if (lhsWidth != -1 && rhsWidth != -1)
4971 resultWidth = std::min(lhsWidth, rhsWidth);
4972 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4977 std::optional<Location> loc) {
4978 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4979 bool isConstResult =
false;
4983 if (lhsWidth != -1 && rhsWidth != -1) {
4984 resultWidth = std::max(lhsWidth, rhsWidth);
4985 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
4988 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
4992 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
4996 std::optional<Location> loc) {
4997 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5000 auto lhsVec = type_cast<FVectorType>(lhs);
5001 auto rhsVec = type_cast<FVectorType>(rhs);
5003 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5008 rhsVec.getElementTypePreservingConst(), loc);
5011 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5012 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5013 lhsVec.isConst() && rhsVec.isConst() &&
5014 elemBaseType.isConst());
5018 std::optional<Location> loc) {
5019 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5023 std::optional<Location> loc) {
5024 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5025 bool isConstResult =
false;
5029 if (lhsWidth != -1 && rhsWidth != -1)
5030 resultWidth = lhsWidth + rhsWidth;
5031 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5035 std::optional<Location> loc) {
5036 auto lhsi = type_dyn_cast<IntType>(lhs);
5037 auto rhsui = type_dyn_cast<UIntType>(rhs);
5038 if (!rhsui || !lhsi)
5040 loc,
"first operand should be integer, second unsigned int");
5044 auto width = lhsi.getWidthOrSentinel();
5045 if (width == -1 || !rhsui.getWidth().has_value()) {
5048 auto amount = *rhsui.getWidth();
5051 "shift amount too large: second operand of "
5052 "dshl is wider than 31 bits");
5053 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5054 if (newWidth > INT32_MAX)
5056 loc,
"shift amount too large: first operand shifted by maximum "
5057 "amount exceeds maximum width");
5060 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5061 lhsi.
isConst() && rhsui.isConst());
5065 std::optional<Location> loc) {
5066 auto lhsi = type_dyn_cast<IntType>(lhs);
5067 auto rhsu = type_dyn_cast<UIntType>(rhs);
5070 loc,
"first operand should be integer, second unsigned int");
5071 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5075 std::optional<Location> loc) {
5076 auto lhsi = type_dyn_cast<IntType>(lhs);
5077 auto rhsu = type_dyn_cast<UIntType>(rhs);
5080 loc,
"first operand should be integer, second unsigned int");
5081 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5089 std::optional<Location> loc) {
5090 return UIntType::get(input.getContext(), 32);
5094 std::optional<Location> loc) {
5095 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5098 int32_t width = base.getBitWidthOrSentinel();
5101 return SIntType::get(input.getContext(), width, base.
isConst());
5105 std::optional<Location> loc) {
5106 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5109 int32_t width = base.getBitWidthOrSentinel();
5112 return UIntType::get(input.getContext(), width, base.
isConst());
5116 std::optional<Location> loc) {
5117 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5120 "operand must be single bit scalar base type");
5121 int32_t width = base.getBitWidthOrSentinel();
5122 if (width == -2 || width == 0 || width > 1)
5124 return AsyncResetType::get(input.getContext(), base.
isConst());
5128 std::optional<Location> loc) {
5129 return ClockType::get(input.getContext(),
isConst(input));
5133 std::optional<Location> loc) {
5134 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5135 auto width = uiType.getWidthOrSentinel();
5138 return SIntType::get(input.getContext(), width, uiType.
isConst());
5141 if (type_isa<SIntType>(input))
5148 std::optional<Location> loc) {
5149 auto inputi = type_dyn_cast<IntType>(input);
5152 int32_t width = inputi.getWidthOrSentinel();
5155 return SIntType::get(input.getContext(), width, inputi.
isConst());
5159 std::optional<Location> loc) {
5160 auto inputi = type_dyn_cast<IntType>(input);
5163 if (isa<UIntType>(inputi))
5165 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5170 std::optional<Location> loc) {
5171 return UIntType::get(input.getContext(), 1,
isConst(input));
5180 std::optional<Location> loc) {
5181 auto inputi = type_dyn_cast<IntType>(input);
5184 loc,
"input type should be the int type but got ", input);
5189 loc,
"high must be equal or greater than low, but got high = ", high,
5197 int32_t width = inputi.getWidthOrSentinel();
5198 if (width != -1 && high >= width)
5201 "high must be smaller than the width of input, but got high = ", high,
5202 ", width = ", width);
5204 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5208 std::optional<Location> loc) {
5210 auto inputi = type_dyn_cast<IntType>(input);
5211 if (amount < 0 || !inputi)
5213 loc,
"operand must have integer type and amount must be >= 0");
5215 int32_t width = inputi.getWidthOrSentinel();
5216 if (width != -1 && amount > width)
5219 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5234 bool isConstCondition,
5235 std::optional<Location> loc) {
5241 if (high.getTypeID() != low.getTypeID())
5242 return emitInferRetTypeError<FIRRTLBaseType>(
5243 loc,
"incompatible mux operand types, true value type: ", high,
5244 ", false value type: ", low);
5246 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5251 if (type_isa<IntType>(low)) {
5256 if (highWidth == -1)
5258 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5262 auto highVector = type_dyn_cast<FVectorType>(high);
5263 auto lowVector = type_dyn_cast<FVectorType>(low);
5264 if (highVector && lowVector &&
5265 highVector.getNumElements() == lowVector.getNumElements()) {
5267 lowVector.getElementTypePreservingConst(),
5268 isConstCondition, loc);
5271 return FVectorType::get(inner, lowVector.getNumElements(),
5276 auto highBundle = type_dyn_cast<BundleType>(high);
5277 auto lowBundle = type_dyn_cast<BundleType>(low);
5278 if (highBundle && lowBundle) {
5279 auto highElements = highBundle.getElements();
5280 auto lowElements = lowBundle.getElements();
5283 SmallVector<BundleType::BundleElement> newElements;
5285 bool failed =
false;
5287 if (highElements[i].name != lowElements[i].name ||
5288 highElements[i].isFlip != lowElements[i].isFlip) {
5292 auto element = highElements[i];
5294 highBundle.getElementTypePreservingConst(i),
5295 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5298 newElements.push_back(element);
5301 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5303 return emitInferRetTypeError<FIRRTLBaseType>(
5304 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5305 ", false value type: ", low);
5310 return emitInferRetTypeError<FIRRTLBaseType>(
5311 loc,
"invalid mux operand types, true value type: ", high,
5312 ", false value type: ", low);
5317 std::optional<Location> loc) {
5318 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5319 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5320 if (!highType || !lowType)
5325FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5326 DictionaryAttr attrs,
5327 OpaqueProperties properties,
5328 mlir::RegionRange regions,
5329 std::optional<Location> loc) {
5330 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5331 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5332 if (!highType || !lowType)
5338FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5339 DictionaryAttr attrs,
5340 OpaqueProperties properties,
5341 mlir::RegionRange regions,
5342 std::optional<Location> loc) {
5343 SmallVector<FIRRTLBaseType> types;
5345 for (
unsigned i = 1; i < 5; i++) {
5346 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5351 isConst(operands[0].getType()), loc);
5355 result = types.back();
5362 std::optional<Location> loc) {
5363 auto inputi = type_dyn_cast<IntType>(input);
5364 if (amount < 0 || !inputi)
5366 loc,
"pad input must be integer and amount must be >= 0");
5368 int32_t width = inputi.getWidthOrSentinel();
5372 width = std::max<int32_t>(width, amount);
5373 return IntType::get(input.getContext(), inputi.isSigned(), width,
5378 std::optional<Location> loc) {
5379 auto inputi = type_dyn_cast<IntType>(input);
5380 if (amount < 0 || !inputi)
5382 loc,
"shl input must be integer and amount must be >= 0");
5384 int32_t width = inputi.getWidthOrSentinel();
5388 return IntType::get(input.getContext(), inputi.isSigned(), width,
5393 std::optional<Location> loc) {
5394 auto inputi = type_dyn_cast<IntType>(input);
5395 if (amount < 0 || !inputi)
5397 loc,
"shr input must be integer and amount must be >= 0");
5399 int32_t width = inputi.getWidthOrSentinel();
5402 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5403 width = std::max<int32_t>(minWidth, width - amount);
5406 return IntType::get(input.getContext(), inputi.isSigned(), width,
5411 std::optional<Location> loc) {
5413 auto inputi = type_dyn_cast<IntType>(input);
5414 if (amount < 0 || !inputi)
5416 loc,
"tail input must be integer and amount must be >= 0");
5418 int32_t width = inputi.getWidthOrSentinel();
5422 loc,
"amount must be less than or equal operand width");
5433void VerbatimExprOp::getAsmResultNames(
5434 function_ref<
void(Value, StringRef)> setNameFn) {
5438 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5439 auto name = getText();
5441 if (name.starts_with(
"`"))
5442 name = name.drop_front();
5443 name = name.take_while(isOkCharacter);
5445 setNameFn(getResult(), name);
5452void VerbatimWireOp::getAsmResultNames(
5453 function_ref<
void(Value, StringRef)> setNameFn) {
5457 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5458 auto name = getText();
5460 if (name.starts_with(
"`"))
5461 name = name.drop_front();
5462 name = name.take_while(isOkCharacter);
5464 setNameFn(getResult(), name);
5475 op->emitError() <<
"unknown width is not allowed for DPI";
5476 return WalkResult::interrupt();
5478 if (width == 1 || width == 8 || width == 16 || width == 32 ||
5480 return WalkResult::advance();
5482 <<
"integer types used by DPI functions must have a "
5483 "specific bit width; "
5484 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5485 "32(int), 64(longint) "
5486 "or greater than 64, but got "
5488 return WalkResult::interrupt();
5493LogicalResult DPICallIntrinsicOp::verify() {
5494 if (
auto inputNames = getInputNames()) {
5495 if (getInputs().size() != inputNames->size())
5496 return emitError() <<
"inputNames has " << inputNames->size()
5497 <<
" elements but there are " << getInputs().size()
5498 <<
" input arguments";
5500 if (
auto outputName = getOutputName())
5501 if (getNumResults() == 0)
5502 return emitError() <<
"output name is given but there is no result";
5504 auto checkType = [
this](Type type) {
5507 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5508 llvm::all_of(this->getOperandTypes(), checkType));
5511SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5512DPICallIntrinsicOp::computeDataFlow() {
5516 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5518 for (
auto operand : getOperands()) {
5519 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5521 SmallVector<circt::FieldRef> operandFields;
5524 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5528 for (
auto result : getResults())
5531 for (
auto field : operandFields)
5532 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
5542LogicalResult HWStructCastOp::verify() {
5544 BundleType bundleType;
5545 hw::StructType structType;
5546 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5547 structType = dyn_cast<hw::StructType>(getType());
5549 return emitError(
"result type must be a struct");
5550 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5551 structType = dyn_cast<hw::StructType>(getOperand().getType());
5553 return emitError(
"operand type must be a struct");
5555 return emitError(
"either source or result type must be a bundle type");
5558 auto firFields = bundleType.getElements();
5559 auto hwFields = structType.getElements();
5560 if (firFields.size() != hwFields.size())
5561 return emitError(
"bundle and struct have different number of fields");
5563 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5564 if (firFields[findex].name.getValue() != hwFields[findex].name)
5565 return emitError(
"field names don't match '")
5566 << firFields[findex].name.getValue() <<
"', '"
5567 << hwFields[findex].name.getValue() <<
"'";
5571 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5572 return emitError(
"size of field '")
5573 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5580LogicalResult BitCastOp::verify() {
5581 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5583 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5585 if (*inTypeBits == *resTypeBits) {
5588 return emitError(
"cannot cast non-'const' input type ")
5589 << getOperand().getType() <<
" to 'const' result type "
5593 return emitError(
"the bitwidth of input (")
5594 << *inTypeBits <<
") and result (" << *resTypeBits
5597 if (!inTypeBits.has_value())
5598 return emitError(
"bitwidth cannot be determined for input operand type ")
5599 << getInput().getType();
5600 return emitError(
"bitwidth cannot be determined for result type ")
5611 NamedAttrList &resultAttrs) {
5612 auto result = parser.parseOptionalAttrDict(resultAttrs);
5613 if (!resultAttrs.get(
"annotations"))
5614 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5620 DictionaryAttr attr,
5621 ArrayRef<StringRef> extraElides = {}) {
5622 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5624 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5625 elidedAttrs.push_back(
"annotations");
5627 elidedAttrs.push_back(
"nameKind");
5629 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5635 NamedAttrList &resultAttrs) {
5638 if (!resultAttrs.get(
"portAnnotations")) {
5639 SmallVector<Attribute, 16> portAnnotations(
5640 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5641 resultAttrs.append(
"portAnnotations",
5642 parser.getBuilder().getArrayAttr(portAnnotations));
5649 DictionaryAttr attr,
5650 ArrayRef<StringRef> extraElides = {}) {
5651 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5653 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5654 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5655 elidedAttrs.push_back(
"portAnnotations");
5664 firrtl::NameKindEnumAttr &result) {
5667 if (!parser.parseOptionalKeyword(&keyword,
5668 {
"interesting_name",
"droppable_name"})) {
5669 auto kind = symbolizeNameKindEnum(keyword);
5670 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
5676 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
5681 firrtl::NameKindEnumAttr attr,
5682 ArrayRef<StringRef> extraElides = {}) {
5683 if (attr.getValue() != NameKindEnum::DroppableName)
5684 p <<
" " << stringifyNameKindEnum(attr.getValue());
5692 NamedAttrList &resultAttrs) {
5700 DictionaryAttr attrs) {
5701 SmallVector<StringRef, 4> elides;
5703 elides.push_back(Forceable::getForceableAttrName());
5712static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5717static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5728 if (ClassType::parseInterface(parser, type))
5735 type.printInterface(p);
5743 NamedAttrList &resultAttrs) {
5744 auto result = p.parseOptionalAttrDict(resultAttrs);
5745 if (!resultAttrs.get(
"name"))
5746 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5752 DictionaryAttr attr,
5753 ArrayRef<StringRef> extraElides = {}) {
5754 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5755 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5756 elides.push_back(
"name");
5758 p.printOptionalAttrDict(op->getAttrs(), elides);
5762 NamedAttrList &resultAttrs) {
5767 DictionaryAttr attr) {
5776 DictionaryAttr attr) {
5785 DictionaryAttr attr) {
5794 OpAsmSetValueNameFn setNameFn) {
5797 if (op->getNumResults() == 1)
5798 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5799 setNameFn(op->getResult(0), nameAttr.getValue());
5802void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5806void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5810void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5814void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5817void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5820void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5823void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5826void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5829void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5832void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5835void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5838void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5841void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5844void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5847void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5850void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5853void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5856void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5859void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5862void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5865void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5868void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5871void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5874void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5877void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5880void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5883void PlusArgsValueIntrinsicOp::getAsmResultNames(
5884 OpAsmSetValueNameFn setNameFn) {
5887void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5890void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5893void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5896void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5899void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5902void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5905void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5908void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5911void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5914void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5917void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5920void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5923void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5926void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5929void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5932void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5935void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5939void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5943void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5947void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5951void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5955void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5959void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5963void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5967void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5971void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5975void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5979void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5983void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5987void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5991void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5995void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5999void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6007void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6011void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6015void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6019void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6023void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6027FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6028 DictionaryAttr attrs,
6029 OpaqueProperties properties,
6030 mlir::RegionRange regions,
6031 std::optional<Location> loc) {
6032 Type inType = operands[0].getType();
6033 auto inRefType = type_dyn_cast<RefType>(inType);
6036 loc,
"ref.resolve operand must be ref type, not ", inType);
6037 return inRefType.getType();
6040FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6041 OpaqueProperties properties,
6042 mlir::RegionRange regions,
6043 std::optional<Location> loc) {
6044 Type inType = operands[0].getType();
6045 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6048 loc,
"ref.send operand must be base type, not ", inType);
6049 return RefType::get(inBaseType.getPassiveType());
6052FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6053 std::optional<Location> loc) {
6054 auto refType = type_dyn_cast<RefType>(type);
6057 auto inType = refType.getType();
6063 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6064 if (fieldIndex < vectorType.getNumElements())
6065 return RefType::get(
6066 vectorType.getElementType().getConstType(
6067 vectorType.isConst() || vectorType.getElementType().isConst()),
6068 refType.getForceable(), refType.getLayer());
6070 "' in RefType of vector type ", refType);
6072 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6073 if (fieldIndex >= bundleType.getNumElements()) {
6075 "subfield element index is greater than "
6076 "the number of fields in the bundle type");
6078 return RefType::get(
6079 bundleType.getElement(fieldIndex)
6081 bundleType.isConst() ||
6082 bundleType.getElement(fieldIndex).type.isConst()),
6083 refType.getForceable(), refType.getLayer());
6087 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6090LogicalResult RefCastOp::verify() {
6093 SmallVector<SymbolRefAttr> missingLayers;
6096 emitOpError(
"cannot discard layer requirements of input reference");
6097 auto ¬e = diag.attachNote();
6098 note <<
"discarding layer requirements: ";
6099 llvm::interleaveComma(missingLayers, note);
6105LogicalResult RefResolveOp::verify() {
6108 SmallVector<SymbolRefAttr> missingLayers;
6111 emitOpError(
"ambient layers are insufficient to resolve reference");
6112 auto ¬e = diag.attachNote();
6113 note <<
"missing layer requirements: ";
6114 interleaveComma(missingLayers, note);
6121 auto targetRef = getTarget();
6122 if (targetRef.getModule() !=
6123 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6124 return emitOpError() <<
"has non-local target";
6126 auto target = ns.
lookup(targetRef);
6128 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6130 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6135 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6136 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6137 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6138 << fType <<
" instead of expected " << getType().getType();
6139 diag.attachNote(loc) <<
"target resolves here";
6145 auto checkLayers = [&](Location loc) -> LogicalResult {
6148 SmallVector<SymbolRefAttr> missingLayers;
6150 auto diag = emitOpError(
"target has insufficient layer requirements");
6151 auto ¬e = diag.attachNote(loc);
6152 note <<
"target is missing layer requirements: ";
6153 llvm::interleaveComma(missingLayers, note);
6158 auto checks = [&](
auto type, Location loc) {
6159 if (failed(checkLayers(loc)))
6161 return checkFinalType(type, loc);
6164 if (target.isPort()) {
6165 auto mod = cast<FModuleLike>(target.getOp());
6166 return checks(mod.getPortType(target.getPort()),
6167 mod.getPortLocation(target.getPort()));
6169 hw::InnerSymbolOpInterface symOp =
6170 cast<hw::InnerSymbolOpInterface>(target.getOp());
6171 if (!symOp.getTargetResult())
6172 return emitOpError(
"has target that cannot be probed")
6173 .attachNote(symOp.getLoc())
6174 .append(
"target resolves here");
6176 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6177 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6178 return emitOpError(
"is not dominated by target")
6179 .attachNote(symOp.getLoc())
6180 .append(
"target here");
6181 return checks(symOp.getTargetResult().getType(), symOp.getLoc());
6188LogicalResult LayerBlockOp::verify() {
6189 auto layerName = getLayerName();
6190 auto *parentOp = (*this)->getParentOp();
6193 while (isa<WhenOp, MatchOp>(parentOp))
6194 parentOp = parentOp->getParentOp();
6198 auto nestedReferences = layerName.getNestedReferences();
6199 if (nestedReferences.empty()) {
6200 if (!isa<FModuleOp>(parentOp)) {
6201 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6202 "not have a 'firrtl.module' op as a parent";
6203 return diag.attachNote(parentOp->getLoc())
6204 <<
"illegal parent op defined here";
6207 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6208 if (!parentLayerBlock) {
6209 auto diag = emitOpError()
6210 <<
"has a nested layer symbol, but does not have a '"
6211 << getOperationName() <<
"' op as a parent'";
6212 return diag.attachNote(parentOp->getLoc())
6213 <<
"illegal parent op defined here";
6215 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6216 if (parentLayerBlockName.getRootReference() !=
6217 layerName.getRootReference() ||
6218 parentLayerBlockName.getNestedReferences() !=
6219 layerName.getNestedReferences().drop_back()) {
6220 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6221 return diag.attachNote(parentLayerBlock->getLoc())
6222 <<
"illegal parent layer block defined here";
6228 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6229 [&](Operation *op) -> WalkResult {
6231 if (isa<LayerBlockOp>(op))
6232 return WalkResult::skip();
6236 for (
auto operand : op->getOperands()) {
6238 if (
auto *definingOp = operand.getDefiningOp())
6242 auto type = operand.getType();
6245 if (isa<PropertyType>(type)) {
6246 auto diag = emitOpError() <<
"captures a property operand";
6247 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6248 diag.attachNote(op->getLoc()) <<
"operand is used here";
6249 return WalkResult::interrupt();
6254 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6256 if (isa<RefDefineOp>(connect))
6257 return WalkResult::advance();
6264 bool passive =
true;
6266 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6267 passive = type.isPassive();
6276 return WalkResult::advance();
6279 return WalkResult::advance();
6283 <<
"connects to a destination which is defined outside its "
6284 "enclosing layer block";
6285 diag.attachNote(getLoc()) <<
"enclosing layer block is defined here";
6286 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6287 return WalkResult::interrupt();
6290 return WalkResult::advance();
6293 return failure(result.wasInterrupted());
6297LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6299 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6301 return emitOpError(
"invalid symbol reference");
6312#define GET_OP_CLASSES
6313#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 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 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 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.