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 = cast<FModuleOp>(arg.getOwner()->getParentOp());
322 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
329 OpAsmSetValueNameFn setNameFn) {
333 auto *block = ®ion.front();
336 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
338 if (!argAttr || argAttr.size() != block->getNumArguments())
341 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
342 auto str = cast<StringAttr>(argAttr[i]).getValue();
344 setNameFn(block->getArgument(i), str);
350 firrtl::NameKindEnumAttr &result);
357struct CompareSymbolRefAttr {
359 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
360 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
365 auto lhsNested = lhs.getNestedReferences();
366 auto rhsNested = rhs.getNestedReferences();
367 auto lhsNestedSize = lhsNested.size();
368 auto rhsNestedSize = rhsNested.size();
369 auto e = std::min(lhsNestedSize, rhsNestedSize);
370 for (
unsigned i = 0; i < e; ++i) {
371 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].getAttr());
377 return lhsNestedSize < rhsNestedSize;
389 for (; op !=
nullptr; op = op->getParentOp()) {
390 if (
auto module = dyn_cast<FModuleLike>(op)) {
391 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
392 result.insert(layers.begin(), layers.end());
395 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
396 result.insert(layerblock.getLayerName());
414 if (
auto type = dyn_cast<RefType>(value.getType()))
415 if (
auto layer = type.getLayer())
416 result.insert(type.getLayer());
425 mlir::SymbolRefAttr dstLayer) {
435 if (srcLayer.getRootReference() != dstLayer.getRootReference())
438 auto srcNames = srcLayer.getNestedReferences();
439 auto dstNames = dstLayer.getNestedReferences();
440 if (dstNames.size() < srcNames.size())
443 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
444 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
451 if (dstLayers.contains(srcLayer))
456 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
465 SmallVectorImpl<SymbolRefAttr> &missing) {
466 for (
auto srcLayer : src)
468 missing.push_back(srcLayer);
470 llvm::sort(missing, CompareSymbolRefAttr());
471 return missing.empty();
478void CircuitOp::build(OpBuilder &builder, OperationState &result,
479 StringAttr name, ArrayAttr annotations) {
481 result.getOrAddProperties<Properties>().setName(name);
484 annotations = builder.getArrayAttr({});
485 result.getOrAddProperties<Properties>().setAnnotations(annotations);
488 Region *bodyRegion = result.addRegion();
490 bodyRegion->push_back(body);
494 NamedAttrList &resultAttrs) {
495 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
496 if (!resultAttrs.get(
"annotations"))
497 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
503 DictionaryAttr attr) {
505 SmallVector<StringRef> elidedAttrs = {
"name"};
507 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
508 if (annotationsAttr.empty())
509 elidedAttrs.push_back(
"annotations");
511 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
514LogicalResult CircuitOp::verifyRegions() {
519 emitOpError(
"must have a non-empty name");
523 mlir::SymbolTable symtbl(getOperation());
525 auto *mainModule = symtbl.lookup(
main);
527 return emitOpError().append(
528 "does not contain module with same name as circuit");
529 if (!isa<FModuleLike>(mainModule))
530 return mainModule->emitError(
531 "entity with name of circuit must be a module");
532 if (symtbl.getSymbolVisibility(mainModule) !=
533 mlir::SymbolTable::Visibility::Public)
534 return mainModule->emitError(
"main module must be public");
539 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
541 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
545 auto defname = extModule.getDefnameAttr();
551 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
552 return extModule.emitOpError()
553 .append(
"attribute 'defname' with value ", defname,
554 " conflicts with the name of another module in the circuit")
555 .attachNote(collidingModule.getLoc())
556 .append(
"previous module declared here");
564 FExtModuleOp collidingExtModule;
565 if (
auto &value = defnameMap[defname]) {
566 collidingExtModule = value;
567 if (!value.getParameters().empty() && extModule.getParameters().empty())
577 SmallVector<PortInfo> ports = extModule.getPorts();
578 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
580 if (ports.size() != collidingPorts.size())
581 return extModule.emitOpError()
582 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
583 " ports which is different from a previously defined "
584 "extmodule with the same 'defname' which has ",
585 collidingPorts.size(),
" ports")
586 .attachNote(collidingExtModule.getLoc())
587 .append(
"previous extmodule definition occurred here");
593 for (
auto p :
llvm::zip(ports, collidingPorts)) {
594 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
595 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
598 return extModule.emitOpError()
599 .append(
"with 'defname' attribute ", defname,
600 " has a port with name ", aName,
601 " which does not match the name of the port in the same "
602 "position of a previously defined extmodule with the same "
603 "'defname', expected port to have name ",
605 .attachNote(collidingExtModule.getLoc())
606 .append(
"previous extmodule definition occurred here");
608 if (!extModule.getParameters().empty() ||
609 !collidingExtModule.getParameters().empty()) {
611 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
612 aType = base.getWidthlessType();
613 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
614 bType = base.getWidthlessType();
617 return extModule.emitOpError()
618 .append(
"with 'defname' attribute ", defname,
619 " has a port with name ", aName,
620 " which has a different type ", aType,
621 " which does not match the type of the port in the same "
622 "position of a previously defined extmodule with the same "
623 "'defname', expected port to have type ",
625 .attachNote(collidingExtModule.getLoc())
626 .append(
"previous extmodule definition occurred here");
631 SmallVector<FModuleOp, 1> dutModules;
634 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
636 dutModules.push_back(moduleOp);
641 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
642 if (verifyExtModule(extModule).failed())
648 if (dutModules.size() > 1) {
649 auto diag = dutModules[0]->emitOpError()
650 <<
"is annotated as the design-under-test (DUT), but other "
651 "modules are also annotated";
652 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
653 diag.attachNote(moduleOp.getLoc()) <<
"is also annotated as the DUT";
660Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
667 SmallVector<PortInfo> results;
668 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
669 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
670 module.getPortDirection(i), module.getPortSymbolAttr(i),
671 module.getPortLocation(i),
672 AnnotationSet::forPort(module, i)});
677SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
679SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
681SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
683SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
686 if (dir == Direction::In)
687 return hw::ModulePort::Direction::Input;
688 if (dir == Direction::Out)
689 return hw::ModulePort::Direction::Output;
690 assert(0 &&
"invalid direction");
695 SmallVector<hw::PortInfo> results;
696 auto aname = StringAttr::get(module.getContext(),
697 hw::HWModuleLike::getPortSymbolAttrName());
698 auto emptyDict = DictionaryAttr::get(module.getContext());
699 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
700 auto sym =
module.getPortSymbolAttr(i);
702 {{
module.getPortNameAttr(i), module.getPortType(i),
703 dirFtoH(module.getPortDirection(i))},
705 sym ? DictionaryAttr::get(
707 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
709 module.getPortLocation(i)});
714SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
715 return ::getPortListImpl(*
this);
718SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
719 return ::getPortListImpl(*
this);
722SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
723 return ::getPortListImpl(*
this);
726SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
727 return ::getPortListImpl(*
this);
731 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
732 dirFtoH(module.getPortDirection(idx))},
736 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
737 StringAttr::get(module.getContext(),
738 hw::HWModuleLike::getPortSymbolAttrName()),
739 module.getPortSymbolAttr(idx)}}),
740 module.getPortLocation(idx)};
744 return ::getPortImpl(*
this, idx);
748 return ::getPortImpl(*
this, idx);
752 return ::getPortImpl(*
this, idx);
756 return ::getPortImpl(*
this, idx);
760BlockArgument FModuleOp::getArgument(
size_t portNumber) {
768 ArrayRef<std::pair<unsigned, PortInfo>> ports,
769 bool supportsInternalPaths =
false) {
772 unsigned oldNumArgs = op.getNumPorts();
773 unsigned newNumArgs = oldNumArgs + ports.size();
776 auto existingDirections = op.getPortDirectionsAttr();
777 ArrayRef<Attribute> existingNames = op.getPortNames();
778 ArrayRef<Attribute> existingTypes = op.getPortTypes();
779 ArrayRef<Attribute> existingLocs = op.getPortLocations();
780 assert(existingDirections.size() == oldNumArgs);
781 assert(existingNames.size() == oldNumArgs);
782 assert(existingTypes.size() == oldNumArgs);
783 assert(existingLocs.size() == oldNumArgs);
784 SmallVector<Attribute> internalPaths;
785 auto emptyInternalPath = InternalPathAttr::get(op.getContext());
786 if (supportsInternalPaths) {
787 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
788 llvm::append_range(internalPaths, internalPathsAttr);
790 internalPaths.resize(oldNumArgs, emptyInternalPath);
791 assert(internalPaths.size() == oldNumArgs);
794 SmallVector<bool> newDirections;
795 SmallVector<Attribute> newNames, newTypes, newAnnos, newSyms, newLocs,
797 newDirections.reserve(newNumArgs);
798 newNames.reserve(newNumArgs);
799 newTypes.reserve(newNumArgs);
800 newAnnos.reserve(newNumArgs);
801 newSyms.reserve(newNumArgs);
802 newLocs.reserve(newNumArgs);
803 newInternalPaths.reserve(newNumArgs);
805 auto emptyArray = ArrayAttr::get(op.getContext(), {});
808 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
809 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
810 newDirections.push_back(existingDirections[oldIdx]);
811 newNames.push_back(existingNames[oldIdx]);
812 newTypes.push_back(existingTypes[oldIdx]);
813 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
814 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
815 newLocs.push_back(existingLocs[oldIdx]);
816 if (supportsInternalPaths)
817 newInternalPaths.push_back(internalPaths[oldIdx]);
821 for (
auto pair : llvm::enumerate(ports)) {
822 auto idx = pair.value().first;
823 auto &port = pair.value().second;
824 migrateOldPorts(idx);
826 newNames.push_back(port.name);
827 newTypes.push_back(TypeAttr::get(port.type));
828 auto annos = port.annotations.getArrayAttr();
829 newAnnos.push_back(annos ? annos : emptyArray);
830 newSyms.push_back(port.sym);
831 newLocs.push_back(port.loc);
832 if (supportsInternalPaths)
833 newInternalPaths.push_back(emptyInternalPath);
835 migrateOldPorts(oldNumArgs);
839 if (llvm::all_of(newAnnos, [](Attribute attr) {
840 return cast<ArrayAttr>(attr).empty();
845 op->setAttr(
"portDirections",
847 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
848 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
849 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
850 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
851 op.setPortSymbols(newSyms);
852 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
853 if (supportsInternalPaths) {
855 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
856 return !cast<InternalPathAttr>(attr).getPath();
859 op->removeAttr(
"internalPaths");
861 op->setAttr(
"internalPaths",
862 ArrayAttr::get(op.getContext(), newInternalPaths));
867static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
868 if (portIndices.none())
872 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
873 ArrayRef<Attribute> portNames = op.getPortNames();
874 ArrayRef<Attribute> portTypes = op.getPortTypes();
875 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
876 ArrayRef<Attribute> portSyms = op.getPortSymbols();
877 ArrayRef<Attribute> portLocs = op.getPortLocations();
878 auto numPorts = op.getNumPorts();
880 assert(portDirections.size() == numPorts);
881 assert(portNames.size() == numPorts);
882 assert(portAnnos.size() == numPorts || portAnnos.empty());
883 assert(portTypes.size() == numPorts);
884 assert(portSyms.size() == numPorts || portSyms.empty());
885 assert(portLocs.size() == numPorts);
887 SmallVector<bool> newPortDirections =
888 removeElementsAtIndices<bool>(portDirections, portIndices);
889 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
896 op->setAttr(
"portDirections",
898 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
899 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
900 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
901 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
902 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
903 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
909 auto internalPaths = op.getInternalPaths();
917 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
918 return !cast<InternalPathAttr>(attr).getPath();
921 op.removeInternalPathsAttr();
923 op.setInternalPathsAttr(ArrayAttr::get(op.getContext(), newPaths));
926void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
927 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
931void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
932 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
936void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
937 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
940void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
941 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
948void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
953 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
956 auto &[index, port] = ports[i];
957 body->insertArgument(index + i, port.type, port.loc);
961void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
966void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
974void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
978template <
typename OpTy>
980 StringAttr name, ArrayRef<PortInfo> ports) {
982 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
983 properties.setSymName(name);
986 SmallVector<Direction, 4> portDirections;
987 SmallVector<Attribute, 4> portNames;
988 SmallVector<Attribute, 4> portTypes;
989 SmallVector<Attribute, 4> portSyms;
990 SmallVector<Attribute, 4> portLocs;
991 for (
const auto &port : ports) {
992 portDirections.push_back(port.direction);
993 portNames.push_back(port.name);
994 portTypes.push_back(TypeAttr::get(port.type));
995 portSyms.push_back(port.sym);
996 portLocs.push_back(port.loc);
999 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1002 properties.setPortDirections(
1004 properties.setPortNames(builder.getArrayAttr(portNames));
1005 properties.setPortTypes(builder.getArrayAttr(portTypes));
1006 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1007 properties.setPortLocations(builder.getArrayAttr(portLocs));
1012template <
typename OpTy>
1014 StringAttr name, ArrayRef<PortInfo> ports,
1015 ArrayAttr annotations, ArrayAttr layers) {
1016 buildModuleLike<OpTy>(builder, result, name, ports);
1017 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1020 annotations = builder.getArrayAttr({});
1021 properties.setAnnotations(annotations);
1025 SmallVector<Attribute, 4> portAnnotations;
1026 for (
const auto &port : ports)
1027 portAnnotations.push_back(port.annotations.getArrayAttr());
1028 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1029 return cast<ArrayAttr>(attr).empty();
1031 portAnnotations.clear();
1032 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1036 layers = builder.getArrayAttr({});
1037 properties.setLayers(layers);
1040template <
typename OpTy>
1041static void buildClass(OpBuilder &builder, OperationState &result,
1042 StringAttr name, ArrayRef<PortInfo> ports) {
1043 return buildModuleLike<OpTy>(builder, result, name, ports);
1046void FModuleOp::build(OpBuilder &builder, OperationState &result,
1047 StringAttr name, ConventionAttr convention,
1048 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1050 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1051 auto &properties = result.getOrAddProperties<Properties>();
1052 properties.setConvention(convention);
1055 auto *bodyRegion = result.regions[0].get();
1057 bodyRegion->push_back(body);
1060 for (
auto &elt : ports)
1061 body->addArgument(elt.type, elt.loc);
1064void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1065 StringAttr name, ConventionAttr convention,
1066 ArrayRef<PortInfo> ports, StringRef defnameAttr,
1067 ArrayAttr annotations, ArrayAttr parameters,
1068 ArrayAttr internalPaths, ArrayAttr layers) {
1069 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1070 auto &properties = result.getOrAddProperties<Properties>();
1071 properties.setConvention(convention);
1072 if (!defnameAttr.empty())
1073 properties.setDefname(builder.getStringAttr(defnameAttr));
1075 parameters = builder.getArrayAttr({});
1076 properties.setParameters(parameters);
1077 if (internalPaths && !internalPaths.empty())
1078 properties.setInternalPaths(internalPaths);
1081void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1082 StringAttr name, ArrayRef<PortInfo> ports,
1083 StringRef intrinsicNameStr, ArrayAttr annotations,
1084 ArrayAttr parameters, ArrayAttr internalPaths,
1086 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1087 auto &properties = result.getOrAddProperties<Properties>();
1088 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1090 parameters = builder.getArrayAttr({});
1091 properties.setParameters(parameters);
1092 if (internalPaths && !internalPaths.empty())
1093 properties.setInternalPaths(internalPaths);
1096void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1097 StringAttr name, ArrayRef<PortInfo> ports,
1098 uint32_t numReadPorts, uint32_t numWritePorts,
1099 uint32_t numReadWritePorts, uint32_t dataWidth,
1100 uint32_t maskBits, uint32_t readLatency,
1101 uint32_t writeLatency, uint64_t depth,
1102 ArrayAttr annotations, ArrayAttr layers) {
1103 auto *context = builder.getContext();
1104 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1105 auto ui32Type = IntegerType::get(context, 32, IntegerType::Unsigned);
1106 auto ui64Type = IntegerType::get(context, 64, IntegerType::Unsigned);
1107 auto &properties = result.getOrAddProperties<Properties>();
1108 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1109 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1110 properties.setNumReadWritePorts(
1111 IntegerAttr::get(ui32Type, numReadWritePorts));
1112 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1113 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1114 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1115 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1116 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1117 properties.setExtraPorts(ArrayAttr::get(context, {}));
1134 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1135 ArrayRef<Attribute> portAnnotations,
1136 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs) {
1139 bool printedNamesDontMatch =
false;
1141 mlir::OpPrintingFlags flags;
1145 SmallString<32> resultNameStr;
1147 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1158 resultNameStr.clear();
1159 llvm::raw_svector_ostream tmpStream(resultNameStr);
1160 p.printOperand(block->getArgument(i), tmpStream);
1163 auto portName = cast<StringAttr>(portNames[i]).getValue();
1164 if (tmpStream.str().drop_front() != portName)
1165 printedNamesDontMatch =
true;
1166 p << tmpStream.str();
1168 p.printKeywordOrString(cast<StringAttr>(portNames[i]).getValue());
1173 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1174 p.printType(portType);
1177 if (!portSyms.empty()) {
1178 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1180 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1186 if (!portAnnotations.empty() &&
1187 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1189 p.printAttribute(portAnnotations[i]);
1196 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1197 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1201 return printedNamesDontMatch;
1208 bool supportsSymbols,
1209 SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1210 SmallVectorImpl<Direction> &portDirections,
1211 SmallVectorImpl<Attribute> &portNames,
1212 SmallVectorImpl<Attribute> &portTypes,
1213 SmallVectorImpl<Attribute> &portAnnotations,
1214 SmallVectorImpl<Attribute> &portSyms,
1215 SmallVectorImpl<Attribute> &portLocs) {
1216 auto *context = parser.getContext();
1218 auto parseArgument = [&]() -> ParseResult {
1220 if (succeeded(parser.parseOptionalKeyword(
"out")))
1221 portDirections.push_back(Direction::Out);
1222 else if (succeeded(parser.parseKeyword(
"in",
"or 'out'")))
1223 portDirections.push_back(Direction::In);
1231 if (hasSSAIdentifiers) {
1232 OpAsmParser::Argument arg;
1233 if (parser.parseArgument(arg))
1235 entryArgs.push_back(arg);
1239 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1240 "Unknown MLIR name");
1241 if (
isdigit(arg.ssaName.name[1]))
1242 portNames.push_back(StringAttr::get(context,
""));
1244 portNames.push_back(
1245 StringAttr::get(context, arg.ssaName.name.drop_front()));
1248 irLoc = arg.ssaName.location;
1252 irLoc = parser.getCurrentLocation();
1253 std::string portName;
1254 if (parser.parseKeywordOrString(&portName))
1256 portNames.push_back(StringAttr::get(context, portName));
1261 if (parser.parseColonType(portType))
1263 portTypes.push_back(TypeAttr::get(portType));
1265 if (hasSSAIdentifiers)
1266 entryArgs.back().type = portType;
1269 if (supportsSymbols) {
1270 hw::InnerSymAttr innerSymAttr;
1271 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1272 NamedAttrList dummyAttrs;
1273 if (parser.parseCustomAttributeWithFallback(
1274 innerSymAttr, ::mlir::Type{},
1276 return ::mlir::failure();
1279 portSyms.push_back(innerSymAttr);
1284 auto parseResult = parser.parseOptionalAttribute(annos);
1285 if (!parseResult.has_value())
1286 annos = parser.getBuilder().getArrayAttr({});
1287 else if (failed(*parseResult))
1289 portAnnotations.push_back(annos);
1292 std::optional<Location> maybeLoc;
1293 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1295 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1296 portLocs.push_back(loc);
1297 if (hasSSAIdentifiers)
1298 entryArgs.back().sourceLoc = loc;
1304 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1310 ArrayAttr parameters) {
1311 if (!parameters || parameters.empty())
1315 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1316 auto paramAttr = cast<ParamDeclAttr>(param);
1317 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1318 if (
auto value = paramAttr.getValue()) {
1320 p.printAttributeWithoutType(value);
1330 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1331 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1332 p << visibility.getValue() <<
' ';
1335 p.printSymbolName(op.getModuleName());
1342 Block *body =
nullptr;
1343 if (!op->getRegion(0).empty())
1344 body = &op->getRegion(0).front();
1347 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1348 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations());
1350 SmallVector<StringRef, 12> omittedAttrs = {
1351 "sym_name",
"portDirections",
"portTypes",
"portAnnotations",
1352 "portSymbols",
"portLocations",
"parameters", visibilityAttrName};
1354 if (op.getConvention() == Convention::Internal)
1355 omittedAttrs.push_back(
"convention");
1359 if (!needPortNamesAttr)
1360 omittedAttrs.push_back(
"portNames");
1363 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1364 omittedAttrs.push_back(
"annotations");
1367 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1369 omittedAttrs.push_back(
"layers");
1371 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1380void FModuleOp::print(OpAsmPrinter &p) {
1386 Region &fbody = getBody();
1387 if (!fbody.empty()) {
1389 p.printRegion(fbody,
false,
1401 SmallVectorImpl<Attribute> ¶meters) {
1403 return parser.parseCommaSeparatedList(
1404 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1409 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1413 if (succeeded(parser.parseOptionalEqual())) {
1414 if (parser.parseAttribute(value, type))
1418 auto &builder = parser.getBuilder();
1419 parameters.push_back(ParamDeclAttr::get(
1420 builder.getContext(), builder.getStringAttr(name), type, value));
1427 ArrayAttr ¶meters) {
1428 SmallVector<Attribute> parseParameters;
1432 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1437template <
typename Properties,
typename =
void>
1440template <
typename Properties>
1442 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1443 : std::true_type {};
1445template <
typename OpTy>
1447 OperationState &result,
1448 bool hasSSAIdentifiers) {
1449 auto *context = result.getContext();
1450 auto &builder = parser.getBuilder();
1451 using Properties =
typename OpTy::Properties;
1452 auto &properties = result.getOrAddProperties<Properties>();
1456 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1459 StringAttr nameAttr;
1460 if (parser.parseSymbolName(nameAttr))
1462 properties.setSymName(nameAttr);
1466 SmallVector<Attribute, 4> parameters;
1469 properties.setParameters(builder.getArrayAttr(parameters));
1473 SmallVector<OpAsmParser::Argument> entryArgs;
1474 SmallVector<Direction, 4> portDirections;
1475 SmallVector<Attribute, 4> portNames;
1476 SmallVector<Attribute, 4> portTypes;
1477 SmallVector<Attribute, 4> portAnnotations;
1478 SmallVector<Attribute, 4> portSyms;
1479 SmallVector<Attribute, 4> portLocs;
1481 entryArgs, portDirections, portNames, portTypes,
1482 portAnnotations, portSyms, portLocs))
1486 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1489 assert(portNames.size() == portTypes.size());
1495 properties.setPortDirections(
1499 properties.setPortNames(builder.getArrayAttr(portNames));
1502 properties.setPortTypes(ArrayAttr::get(context, portTypes));
1506 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1507 return !cast<ArrayAttr>(anno).empty();
1509 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
1511 properties.setPortAnnotations(builder.getArrayAttr({}));
1514 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1515 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1518 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1521 properties.setAnnotations(builder.getArrayAttr({}));
1524 auto *body = result.addRegion();
1526 if (hasSSAIdentifiers) {
1527 if (parser.parseRegion(*body, entryArgs))
1530 body->push_back(
new Block());
1535ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1536 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1539 auto &properties = result.getOrAddProperties<Properties>();
1540 properties.setConvention(
1541 ConventionAttr::get(result.getContext(), Convention::Internal));
1542 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1546ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1547 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1550 auto &properties = result.getOrAddProperties<Properties>();
1551 properties.setConvention(
1552 ConventionAttr::get(result.getContext(), Convention::Internal));
1556ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1557 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1561ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1562 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1566LogicalResult FModuleOp::verify() {
1569 auto portTypes = getPortTypes();
1570 auto portLocs = getPortLocations();
1571 auto numPorts = portTypes.size();
1574 if (body->getNumArguments() != numPorts)
1575 return emitOpError(
"entry block must have ")
1576 << numPorts <<
" arguments to match module signature";
1579 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1580 if (arg.getType() != cast<TypeAttr>(type).getValue())
1581 return emitOpError(
"block argument types should match signature types");
1582 if (arg.getLoc() != cast<LocationAttr>(loc))
1584 "block argument locations should match signature locations");
1592 std::optional<::mlir::ArrayAttr> internalPaths) {
1597 if (internalPaths->size() != op.getNumPorts())
1598 return op.emitError(
"module has inconsistent internal path array with ")
1599 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1603 for (
auto [idx, path, typeattr] : llvm::enumerate(
1604 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1605 if (path.getPath() &&
1606 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1608 op.emitError(
"module has internal path for non-ref-type port ")
1609 << op.getPortNameAttr(idx);
1610 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1617LogicalResult FExtModuleOp::verify() {
1621 auto params = getParameters();
1625 auto checkParmValue = [&](Attribute elt) ->
bool {
1626 auto param = cast<ParamDeclAttr>(elt);
1627 auto value = param.getValue();
1628 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1630 emitError() <<
"has unknown extmodule parameter value '"
1631 << param.getName().getValue() <<
"' = " << value;
1635 if (!llvm::all_of(params, checkParmValue))
1641LogicalResult FIntModuleOp::verify() {
1645 auto params = getParameters();
1649 auto checkParmValue = [&](Attribute elt) ->
bool {
1650 auto param = cast<ParamDeclAttr>(elt);
1651 auto value = param.getValue();
1652 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1654 emitError() <<
"has unknown intmodule parameter value '"
1655 << param.getName().getValue() <<
"' = " << value;
1659 if (!llvm::all_of(params, checkParmValue))
1666 CircuitOp circuitOp,
1667 SymbolTableCollection &symbolTable,
1669 auto layer = refType.getLayer();
1672 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1674 return emitError(loc) << start <<
" associated with layer '" << layer
1675 <<
"', but this layer was not defined";
1676 if (!isa<LayerOp>(layerOp)) {
1677 auto diag = emitError(loc)
1678 << start <<
" associated with layer '" << layer
1679 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1680 << LayerOp::getOperationName() <<
"' op";
1681 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1687 SymbolTableCollection &symbolTable) {
1689 auto circuitOp =
module->getParentOfType<CircuitOp>();
1690 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1691 auto type =
module.getPortType(i);
1693 if (
auto refType = type_dyn_cast<RefType>(type)) {
1695 refType, module.getPortLocation(i), circuitOp, symbolTable,
1696 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1701 if (
auto classType = dyn_cast<ClassType>(type)) {
1702 auto className = classType.getNameAttr();
1703 auto classOp = dyn_cast_or_null<ClassLike>(
1704 symbolTable.lookupSymbolIn(circuitOp, className));
1706 return module.emitOpError() << "references unknown class " << className;
1709 if (failed(classOp.verifyType(classType,
1710 [&]() { return module.emitOpError(); })))
1719LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1724 auto circuitOp = (*this)->getParentOfType<CircuitOp>();
1725 for (
auto layer : getLayers()) {
1726 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
1727 return emitOpError() <<
"enables unknown layer '" << layer <<
"'";
1734FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1739FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1744FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
1748void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
1753void FExtModuleOp::getAsmBlockArgumentNames(
1758void FIntModuleOp::getAsmBlockArgumentNames(
1763void FMemModuleOp::getAsmBlockArgumentNames(
1768ArrayAttr FMemModuleOp::getParameters() {
return {}; }
1770ArrayAttr FModuleOp::getParameters() {
return {}; }
1772Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
1774ConventionAttr FIntModuleOp::getConventionAttr() {
1775 return ConventionAttr::get(getContext(), getConvention());
1778Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
1780ConventionAttr FMemModuleOp::getConventionAttr() {
1781 return ConventionAttr::get(getContext(), getConvention());
1789 ClassLike classOp, ClassType type,
1790 function_ref<InFlightDiagnostic()> emitError) {
1792 auto name = type.getNameAttr().getAttr();
1793 auto expectedName = classOp.getModuleNameAttr();
1794 if (name != expectedName)
1795 return emitError() <<
"type has wrong name, got " << name <<
", expected "
1798 auto elements = type.getElements();
1800 auto expectedNumElements = classOp.getNumPorts();
1802 return emitError() <<
"has wrong number of ports, got " <<
numElements
1803 <<
", expected " << expectedNumElements;
1805 auto portNames = classOp.getPortNames();
1806 auto portDirections = classOp.getPortDirections();
1807 auto portTypes = classOp.getPortTypes();
1810 auto element = elements[i];
1812 auto name = element.name;
1813 auto expectedName = portNames[i];
1814 if (name != expectedName)
1815 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
1816 <<
", expected " << expectedName;
1818 auto direction = element.direction;
1819 auto expectedDirection =
Direction(portDirections[i]);
1820 if (direction != expectedDirection)
1821 return emitError() <<
"port " << name <<
" has wrong direction, got "
1825 auto type = element.type;
1826 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
1827 if (type != expectedType)
1828 return emitError() <<
"port " << name <<
" has wrong type, got " << type
1829 <<
", expected " << expectedType;
1836 auto n = classOp.getNumPorts();
1837 SmallVector<ClassElement> elements;
1838 elements.reserve(n);
1839 for (
size_t i = 0; i < n; ++i)
1840 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
1841 classOp.getPortDirection(i)});
1842 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
1843 return ClassType::get(name, elements);
1846template <
typename OpTy>
1848 bool hasSSAIdentifiers) {
1849 auto *context = result.getContext();
1850 auto &builder = parser.getBuilder();
1851 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1855 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1858 StringAttr nameAttr;
1859 if (parser.parseSymbolName(nameAttr))
1861 properties.setSymName(nameAttr);
1864 SmallVector<OpAsmParser::Argument> entryArgs;
1865 SmallVector<Direction, 4> portDirections;
1866 SmallVector<Attribute, 4> portNames;
1867 SmallVector<Attribute, 4> portTypes;
1868 SmallVector<Attribute, 4> portAnnotations;
1869 SmallVector<Attribute, 4> portSyms;
1870 SmallVector<Attribute, 4> portLocs;
1872 false, entryArgs, portDirections,
1873 portNames, portTypes, portAnnotations, portSyms,
1878 for (
auto annos : portAnnotations)
1879 if (!cast<ArrayAttr>(annos).empty())
1883 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1886 assert(portNames.size() == portTypes.size());
1892 properties.setPortDirections(
1896 properties.setPortNames(builder.getArrayAttr(portNames));
1899 properties.setPortTypes(builder.getArrayAttr(portTypes));
1902 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1903 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1906 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1912 auto *bodyRegion = result.addRegion();
1914 if (hasSSAIdentifiers) {
1915 if (parser.parseRegion(*bodyRegion, entryArgs))
1917 if (bodyRegion->empty())
1918 bodyRegion->push_back(
new Block());
1928 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1929 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1930 p << visibility.getValue() <<
' ';
1933 p.printSymbolName(op.getName());
1937 Region ®ion = op->getRegion(0);
1938 Block *body =
nullptr;
1939 if (!region.empty())
1940 body = ®ion.front();
1943 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1944 {}, op.getPortSymbols(), op.getPortLocations());
1947 SmallVector<StringRef, 8> omittedAttrs = {
1948 "sym_name",
"portNames",
"portTypes",
"portDirections",
1949 "portSymbols",
"portLocations", visibilityAttrName};
1953 if (!needPortNamesAttr)
1954 omittedAttrs.push_back(
"portNames");
1956 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1959 if (!region.empty()) {
1961 auto printEntryBlockArgs =
false;
1962 auto printBlockTerminators =
false;
1963 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
1971void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
1972 ArrayRef<PortInfo> ports) {
1975 [](
const auto &port) {
return port.annotations.empty(); }) &&
1976 "class ports may not have annotations");
1978 buildClass<ClassOp>(builder, result, name, ports);
1981 auto *bodyRegion = result.regions[0].get();
1983 bodyRegion->push_back(body);
1986 for (
auto &elt : ports)
1987 body->addArgument(elt.type, elt.loc);
1990void ClassOp::build(::mlir::OpBuilder &odsBuilder,
1991 ::mlir::OperationState &odsState, Twine name,
1992 mlir::ArrayRef<mlir::StringRef> fieldNames,
1993 mlir::ArrayRef<mlir::Type> fieldTypes) {
1995 SmallVector<PortInfo, 10> ports;
1996 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
1997 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
1999 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2002 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2004 auto &body = odsState.regions[0]->getBlocks().front();
2005 auto prevLoc = odsBuilder.saveInsertionPoint();
2006 odsBuilder.setInsertionPointToEnd(&body);
2007 auto args = body.getArguments();
2008 auto loc = odsState.location;
2009 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2010 odsBuilder.create<PropAssignOp>(loc, args[i + 1], args[i]);
2012 odsBuilder.restoreInsertionPoint(prevLoc);
2014void ClassOp::print(OpAsmPrinter &p) {
2018ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2019 auto hasSSAIdentifiers =
true;
2020 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2023LogicalResult ClassOp::verify() {
2025 auto type = operand.getType();
2026 if (!isa<PropertyType>(type)) {
2027 emitOpError(
"ports on a class must be properties");
2036ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2040void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2045SmallVector<PortInfo> ClassOp::getPorts() {
2046 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2049void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2050 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2054void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2055 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2058Convention ClassOp::getConvention() {
return Convention::Internal; }
2060ConventionAttr ClassOp::getConventionAttr() {
2061 return ConventionAttr::get(getContext(), getConvention());
2064ArrayAttr ClassOp::getParameters() {
return {}; }
2066ArrayAttr ClassOp::getPortAnnotationsAttr() {
2067 return ArrayAttr::get(getContext(), {});
2070ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2072void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2073 llvm_unreachable(
"classes do not support annotations");
2076ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2078ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2080SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2081 return ::getPortListImpl(*
this);
2085 return ::getPortImpl(*
this, idx);
2088BlockArgument ClassOp::getArgument(
size_t portNumber) {
2092bool ClassOp::canDiscardOnUseEmpty() {
2103void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2104 StringAttr name, ArrayRef<PortInfo> ports) {
2107 [](
const auto &port) {
return port.annotations.empty(); }) &&
2108 "class ports may not have annotations");
2109 buildClass<ClassOp>(builder, result, name, ports);
2112void ExtClassOp::print(OpAsmPrinter &p) {
2116ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2117 auto hasSSAIdentifiers =
false;
2118 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2122ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2126void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2131SmallVector<PortInfo> ExtClassOp::getPorts() {
2132 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2135void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2136 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2139void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2140 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2143Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2145ConventionAttr ExtClassOp::getConventionAttr() {
2146 return ConventionAttr::get(getContext(), getConvention());
2149ArrayAttr ExtClassOp::getLayersAttr() {
2150 return ArrayAttr::get(getContext(), {});
2153ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2155ArrayAttr ExtClassOp::getParameters() {
return {}; }
2157ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2158 return ArrayAttr::get(getContext(), {});
2161ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2163void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2164 llvm_unreachable(
"classes do not support annotations");
2167SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2168 return ::getPortListImpl(*
this);
2172 return ::getPortImpl(*
this, idx);
2175bool ExtClassOp::canDiscardOnUseEmpty() {
2186LogicalResult LayerOp::verify() {
2197 if (getConvention() == LayerConvention::Bind) {
2198 Operation *parentOp = (*this)->getParentOp();
2199 while (
auto parentLayer = dyn_cast<LayerOp>(parentOp)) {
2200 if (parentLayer.getConvention() == LayerConvention::Inline) {
2201 auto diag = emitOpError() <<
"has bind convention and cannot be nested "
2202 "under a layer with inline convention";
2203 diag.attachNote(parentLayer.getLoc())
2204 <<
"layer with inline convention here";
2207 parentOp = parentOp->getParentOp();
2218void InstanceOp::build(
2219 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2220 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2221 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2222 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2223 ArrayRef<Attribute> layers,
bool lowerToBind, StringAttr innerSym) {
2224 build(builder, result, resultTypes, moduleName, name, nameKind,
2225 portDirections, portNames, annotations, portAnnotations, layers,
2227 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2230void InstanceOp::build(
2231 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2232 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2233 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2234 ArrayRef<Attribute> annotations, ArrayRef<Attribute> portAnnotations,
2235 ArrayRef<Attribute> layers,
bool lowerToBind, hw::InnerSymAttr innerSym) {
2236 result.addTypes(resultTypes);
2237 result.getOrAddProperties<Properties>().setModuleName(
2238 SymbolRefAttr::get(builder.getContext(), moduleName));
2239 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2240 result.getOrAddProperties<Properties>().setPortDirections(
2242 result.getOrAddProperties<Properties>().setPortNames(
2243 builder.getArrayAttr(portNames));
2244 result.getOrAddProperties<Properties>().setAnnotations(
2245 builder.getArrayAttr(annotations));
2246 result.getOrAddProperties<Properties>().setLayers(
2247 builder.getArrayAttr(layers));
2249 result.getOrAddProperties<Properties>().setLowerToBind(
2250 builder.getUnitAttr());
2252 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2254 result.getOrAddProperties<Properties>().setNameKind(
2255 NameKindEnumAttr::get(builder.getContext(), nameKind));
2257 if (portAnnotations.empty()) {
2258 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2259 builder.getArrayAttr({}));
2260 result.getOrAddProperties<Properties>().setPortAnnotations(
2261 builder.getArrayAttr(portAnnotationsVec));
2263 assert(portAnnotations.size() == resultTypes.size());
2264 result.getOrAddProperties<Properties>().setPortAnnotations(
2265 builder.getArrayAttr(portAnnotations));
2269void InstanceOp::build(OpBuilder &builder, OperationState &result,
2270 FModuleLike module, StringRef name,
2271 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2272 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2273 hw::InnerSymAttr innerSym) {
2276 SmallVector<Type> resultTypes;
2277 resultTypes.reserve(module.getNumPorts());
2279 module.getPortTypes(), std::back_inserter(resultTypes),
2280 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2283 ArrayAttr portAnnotationsAttr;
2284 if (portAnnotations.empty()) {
2285 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2286 resultTypes.size(), builder.getArrayAttr({})));
2288 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2292 builder, result, resultTypes,
2293 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2294 builder.getStringAttr(name),
2295 NameKindEnumAttr::get(builder.getContext(), nameKind),
2296 module.getPortDirectionsAttr(), module.getPortNamesAttr(),
2297 builder.getArrayAttr(annotations), portAnnotationsAttr,
2298 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2302void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2303 ArrayRef<PortInfo> ports, StringRef moduleName,
2304 StringRef name, NameKindEnum nameKind,
2305 ArrayRef<Attribute> annotations,
2306 ArrayRef<Attribute> layers,
bool lowerToBind,
2307 hw::InnerSymAttr innerSym) {
2309 SmallVector<Type> newResultTypes;
2310 SmallVector<Direction> newPortDirections;
2311 SmallVector<Attribute> newPortNames;
2312 SmallVector<Attribute> newPortAnnotations;
2313 for (
auto &p : ports) {
2314 newResultTypes.push_back(p.type);
2315 newPortDirections.push_back(p.direction);
2316 newPortNames.push_back(p.name);
2317 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2320 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2321 newPortDirections, newPortNames, annotations, newPortAnnotations,
2322 layers, lowerToBind, innerSym);
2325LogicalResult InstanceOp::verify() {
2328 SmallVector<SymbolRefAttr> missingLayers;
2329 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2331 missingLayers.push_back(layer);
2333 if (missingLayers.empty())
2337 emitOpError(
"ambient layers are insufficient to instantiate module");
2338 auto ¬e = diag.attachNote();
2339 note <<
"missing layer requirements: ";
2340 interleaveComma(missingLayers, note);
2346InstanceOp InstanceOp::erasePorts(OpBuilder &builder,
2347 const llvm::BitVector &portIndices) {
2348 assert(portIndices.size() >= getNumResults() &&
2349 "portIndices is not at least as large as getNumResults()");
2351 if (portIndices.none())
2354 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2355 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2356 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2358 SmallVector<Attribute> newPortNames =
2360 SmallVector<Attribute> newPortAnnotations =
2363 auto newOp = builder.create<InstanceOp>(
2364 getLoc(), newResultTypes, getModuleName(),
getName(), getNameKind(),
2365 newPortDirections, newPortNames, getAnnotations().getValue(),
2366 newPortAnnotations, getLayers(), getLowerToBind(), getInnerSymAttr());
2368 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2369 oldIdx != numOldPorts; ++oldIdx) {
2370 if (portIndices.test(oldIdx)) {
2371 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2374 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2382 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2383 newOp->setAttr(
"output_file", outputFile);
2388ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2389 assert(portIdx < getNumResults() &&
2390 "index should be smaller than result number");
2391 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2394void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2395 assert(annotations.size() == getNumResults() &&
2396 "number of annotations is not equal to result number");
2397 (*this)->setAttr(
"portAnnotations",
2398 ArrayAttr::get(getContext(), annotations));
2402InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2403 auto portSize = ports.size();
2404 auto newPortCount = getNumResults() + portSize;
2405 SmallVector<Direction> newPortDirections;
2406 newPortDirections.reserve(newPortCount);
2407 SmallVector<Attribute> newPortNames;
2408 newPortNames.reserve(newPortCount);
2409 SmallVector<Type> newPortTypes;
2410 newPortTypes.reserve(newPortCount);
2411 SmallVector<Attribute> newPortAnnos;
2412 newPortAnnos.reserve(newPortCount);
2414 unsigned oldIndex = 0;
2415 unsigned newIndex = 0;
2416 while (oldIndex + newIndex < newPortCount) {
2418 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2419 auto &newPort = ports[newIndex].second;
2420 newPortDirections.push_back(newPort.direction);
2421 newPortNames.push_back(newPort.name);
2422 newPortTypes.push_back(newPort.type);
2423 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2427 newPortDirections.push_back(getPortDirection(oldIndex));
2428 newPortNames.push_back(getPortName(oldIndex));
2429 newPortTypes.push_back(getType(oldIndex));
2430 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2436 return OpBuilder(*this).create<InstanceOp>(
2437 getLoc(), newPortTypes, getModuleName(),
getName(), getNameKind(),
2438 newPortDirections, newPortNames, getAnnotations().getValue(),
2439 newPortAnnos, getLayers(), getLowerToBind(), getInnerSymAttr());
2442LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2444 getModuleNameAttr());
2447StringRef InstanceOp::getInstanceName() {
return getName(); }
2449StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2451void InstanceOp::print(OpAsmPrinter &p) {
2454 p.printKeywordOrString(
getName());
2455 if (
auto attr = getInnerSymAttr()) {
2457 p.printSymbolName(attr.getSymName());
2459 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2460 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2463 SmallVector<StringRef, 10> omittedAttrs = {
2464 "moduleName",
"name",
"portDirections",
2465 "portNames",
"portTypes",
"portAnnotations",
2466 "inner_sym",
"nameKind"};
2467 if (getAnnotations().
empty())
2468 omittedAttrs.push_back(
"annotations");
2469 if (getLayers().
empty())
2470 omittedAttrs.push_back(
"layers");
2471 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2475 p.printSymbolName(getModuleName());
2478 SmallVector<Attribute> portTypes;
2479 portTypes.reserve(getNumResults());
2480 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2483 getPortNames().getValue(), portTypes,
2484 getPortAnnotations().getValue(), {}, {});
2487ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2488 auto *context = parser.getContext();
2489 auto &properties = result.getOrAddProperties<Properties>();
2492 hw::InnerSymAttr innerSymAttr;
2493 FlatSymbolRefAttr moduleName;
2494 SmallVector<OpAsmParser::Argument> entryArgs;
2495 SmallVector<Direction, 4> portDirections;
2496 SmallVector<Attribute, 4> portNames;
2497 SmallVector<Attribute, 4> portTypes;
2498 SmallVector<Attribute, 4> portAnnotations;
2499 SmallVector<Attribute, 4> portSyms;
2500 SmallVector<Attribute, 4> portLocs;
2501 NameKindEnumAttr nameKind;
2503 if (parser.parseKeywordOrString(&name))
2505 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2506 if (parser.parseCustomAttributeWithFallback(
2507 innerSymAttr, ::mlir::Type{},
2509 result.attributes)) {
2510 return ::mlir::failure();
2514 parser.parseOptionalAttrDict(result.attributes) ||
2515 parser.parseAttribute(moduleName) ||
2517 false, entryArgs, portDirections,
2518 portNames, portTypes, portAnnotations, portSyms,
2525 properties.setModuleName(moduleName);
2526 properties.setName(StringAttr::get(context, name));
2527 properties.setNameKind(nameKind);
2528 properties.setPortDirections(
2530 properties.setPortNames(ArrayAttr::get(context, portNames));
2531 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2535 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2536 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2539 result.types.reserve(portTypes.size());
2541 portTypes, std::back_inserter(result.types),
2542 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2547void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2552 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2553 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2557std::optional<size_t> InstanceOp::getTargetResultIndex() {
2559 return std::nullopt;
2566void InstanceChoiceOp::build(
2567 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2568 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2569 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2570 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2572 SmallVector<Type> resultTypes;
2573 for (Attribute portType : defaultModule.getPortTypes())
2574 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2577 ArrayAttr portAnnotationsAttr;
2578 if (portAnnotations.empty()) {
2579 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2580 resultTypes.size(), builder.getArrayAttr({})));
2582 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2586 SmallVector<Attribute> moduleNames, caseNames;
2587 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2588 for (
auto [caseOption, caseModule] : cases) {
2589 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2590 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2591 {SymbolRefAttr::get(caseOption)}));
2592 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2595 return build(builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2596 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2597 NameKindEnumAttr::get(builder.getContext(), nameKind),
2598 defaultModule.getPortDirectionsAttr(),
2599 defaultModule.getPortNamesAttr(),
2600 builder.getArrayAttr(annotations), portAnnotationsAttr,
2601 defaultModule.getLayersAttr(),
2602 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2605std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2606 return std::nullopt;
2609void InstanceChoiceOp::print(OpAsmPrinter &p) {
2612 p.printKeywordOrString(
getName());
2613 if (
auto attr = getInnerSymAttr()) {
2615 p.printSymbolName(attr.getSymName());
2617 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2618 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2621 SmallVector<StringRef, 10> omittedAttrs = {
2622 "moduleNames",
"caseNames",
"name",
2623 "portDirections",
"portNames",
"portTypes",
2624 "portAnnotations",
"inner_sym",
"nameKind"};
2625 if (getAnnotations().
empty())
2626 omittedAttrs.push_back(
"annotations");
2627 if (getLayers().
empty())
2628 omittedAttrs.push_back(
"layers");
2629 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2634 auto moduleNames = getModuleNamesAttr();
2635 auto caseNames = getCaseNamesAttr();
2637 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2639 p <<
" alternatives ";
2641 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2643 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2647 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2648 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2650 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2656 SmallVector<Attribute> portTypes;
2657 portTypes.reserve(getNumResults());
2658 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2661 getPortNames().getValue(), portTypes,
2662 getPortAnnotations().getValue(), {}, {});
2665ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2666 OperationState &result) {
2667 auto *context = parser.getContext();
2668 auto &properties = result.getOrAddProperties<Properties>();
2671 hw::InnerSymAttr innerSymAttr;
2672 SmallVector<Attribute> moduleNames;
2673 SmallVector<Attribute> caseNames;
2674 SmallVector<OpAsmParser::Argument> entryArgs;
2675 SmallVector<Direction, 4> portDirections;
2676 SmallVector<Attribute, 4> portNames;
2677 SmallVector<Attribute, 4> portTypes;
2678 SmallVector<Attribute, 4> portAnnotations;
2679 SmallVector<Attribute, 4> portSyms;
2680 SmallVector<Attribute, 4> portLocs;
2681 NameKindEnumAttr nameKind;
2683 if (parser.parseKeywordOrString(&name))
2685 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2686 if (parser.parseCustomAttributeWithFallback(
2687 innerSymAttr, Type{},
2689 result.attributes)) {
2694 parser.parseOptionalAttrDict(result.attributes))
2697 FlatSymbolRefAttr defaultModuleName;
2698 if (parser.parseAttribute(defaultModuleName))
2700 moduleNames.push_back(defaultModuleName);
2704 FlatSymbolRefAttr optionName;
2705 if (parser.parseKeyword(
"alternatives") ||
2706 parser.parseAttribute(optionName) || parser.parseLBrace())
2709 FlatSymbolRefAttr moduleName;
2710 StringAttr caseName;
2711 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
2712 if (parser.parseArrow() || parser.parseAttribute(moduleName))
2714 moduleNames.push_back(moduleName);
2715 caseNames.push_back(SymbolRefAttr::get(
2716 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
2717 if (failed(parser.parseOptionalComma()))
2720 if (parser.parseRBrace())
2725 false, entryArgs, portDirections,
2726 portNames, portTypes, portAnnotations, portSyms,
2732 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
2733 properties.setCaseNames(ArrayAttr::get(context, caseNames));
2734 properties.setName(StringAttr::get(context, name));
2735 properties.setNameKind(nameKind);
2736 properties.setPortDirections(
2738 properties.setPortNames(ArrayAttr::get(context, portNames));
2739 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2743 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2744 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2747 result.types.reserve(portTypes.size());
2749 portTypes, std::back_inserter(result.types),
2750 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2755void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2757 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
2758 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
2761LogicalResult InstanceChoiceOp::verify() {
2762 if (getCaseNamesAttr().
empty())
2763 return emitOpError() <<
"must have at least one case";
2764 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
2765 return emitOpError() <<
"number of referenced modules does not match the "
2766 "number of options";
2771 SmallVector<SymbolRefAttr> missingLayers;
2772 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2774 missingLayers.push_back(layer);
2776 if (missingLayers.empty())
2780 emitOpError(
"ambient layers are insufficient to instantiate module");
2781 auto ¬e = diag.attachNote();
2782 note <<
"missing layer requirements: ";
2783 interleaveComma(missingLayers, note);
2788InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2789 auto caseNames = getCaseNamesAttr();
2790 for (
auto moduleName : getModuleNamesAttr()) {
2792 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
2796 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
2797 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2798 auto ref = cast<SymbolRefAttr>(caseNames[i]);
2799 auto refRoot = ref.getRootReference();
2800 if (ref.getRootReference() != root)
2801 return emitOpError() <<
"case " << ref
2802 <<
" is not in the same option group as "
2805 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
2806 return emitOpError() <<
"option " << refRoot <<
" does not exist";
2808 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
2809 return emitOpError() <<
"option " << refRoot
2810 <<
" does not contain option case " << ref;
2817InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
2818 auto caseNames = getCaseNamesAttr();
2819 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2820 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
2821 if (caseSym == option.getSymName())
2822 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
2824 return getDefaultTargetAttr();
2827SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
2828InstanceChoiceOp::getTargetChoices() {
2829 auto caseNames = getCaseNamesAttr();
2830 auto moduleNames = getModuleNamesAttr();
2831 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
2832 for (
size_t i = 0; i < caseNames.size(); ++i) {
2833 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
2834 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
2841InstanceChoiceOp::erasePorts(OpBuilder &builder,
2842 const llvm::BitVector &portIndices) {
2843 assert(portIndices.size() >= getNumResults() &&
2844 "portIndices is not at least as large as getNumResults()");
2846 if (portIndices.none())
2849 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2850 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2851 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2853 SmallVector<Attribute> newPortNames =
2855 SmallVector<Attribute> newPortAnnotations =
2858 auto newOp = builder.create<InstanceChoiceOp>(
2859 getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
getName(),
2861 ArrayAttr::get(getContext(), newPortNames), getAnnotationsAttr(),
2862 ArrayAttr::get(getContext(), newPortAnnotations), getLayers(),
2865 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2866 oldIdx != numOldPorts; ++oldIdx) {
2867 if (portIndices.test(oldIdx)) {
2868 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2871 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2879 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2880 newOp->setAttr(
"output_file", outputFile);
2889ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
2890 assert(portIdx < getNumResults() &&
2891 "index should be smaller than result number");
2892 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2895void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2896 assert(annotations.size() == getNumResults() &&
2897 "number of annotations is not equal to result number");
2898 (*this)->setAttr(
"portAnnotations",
2899 ArrayAttr::get(getContext(), annotations));
2903void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
2904 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
2907 numReadWritePorts = 0;
2909 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2910 auto portKind = getPortKind(i);
2911 if (portKind == MemOp::PortKind::Debug)
2913 else if (portKind == MemOp::PortKind::Read)
2915 else if (portKind == MemOp::PortKind::Write) {
2918 ++numReadWritePorts;
2923LogicalResult MemOp::verify() {
2927 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
2933 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
2934 auto portName = getPortName(i);
2939 BundleType portBundleType =
2940 type_dyn_cast<BundleType>(getResult(i).getType());
2943 if (!portNamesSet.insert(portName).second) {
2944 emitOpError() <<
"has non-unique port name " << portName;
2952 auto elt = getPortNamed(portName);
2954 emitOpError() <<
"could not get port with name " << portName;
2957 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
2960 if (portKind == MemOp::PortKind::Debug &&
2961 !type_isa<RefType>(getResult(i).getType()))
2962 return emitOpError() <<
"has an invalid type on port " << portName
2963 <<
" (expected Read/Write/ReadWrite/Debug)";
2964 if (type_isa<RefType>(firrtlType) && e == 1)
2965 return emitOpError()
2966 <<
"cannot have only one port of debug type. Debug port can only "
2967 "exist alongside other read/write/read-write port";
2972 if (portKind == MemOp::PortKind::Debug) {
2973 auto resType = type_cast<RefType>(getResult(i).getType());
2974 if (!(resType && type_isa<FVectorType>(resType.getType())))
2975 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
2976 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
2978 auto dataTypeOption = portBundleType.getElement(
"data");
2979 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
2980 dataTypeOption = portBundleType.getElement(
"wdata");
2981 if (!dataTypeOption) {
2982 emitOpError() <<
"has no data field on port " << portName
2983 <<
" (expected to see \"data\" for a read or write "
2984 "port or \"rdata\" for a read/write port)";
2987 dataType = dataTypeOption->type;
2989 if (portKind == MemOp::PortKind::Read) {
2996 emitOpError() <<
"has non-passive data type on port " << portName
2997 <<
" (memory types must be passive)";
3002 if (dataType.containsAnalog()) {
3003 emitOpError() <<
"has a data type that contains an analog type on port "
3005 <<
" (memory types cannot contain analog types)";
3013 getTypeForPort(getDepth(), dataType, portKind,
3014 dataType.isGround() ? getMaskBits() : 0);
3017 auto originalType = getResult(i).getType();
3018 if (originalType != expectedType) {
3019 StringRef portKindName;
3021 case MemOp::PortKind::Read:
3022 portKindName =
"read";
3024 case MemOp::PortKind::Write:
3025 portKindName =
"write";
3027 case MemOp::PortKind::ReadWrite:
3028 portKindName =
"readwrite";
3030 case MemOp::PortKind::Debug:
3031 portKindName =
"dbg";
3034 emitOpError() <<
"has an invalid type for port " << portName
3035 <<
" of determined kind \"" << portKindName
3036 <<
"\" (expected " << expectedType <<
", but got "
3037 << originalType <<
")";
3043 if (oldDataType && oldDataType != dataType) {
3044 emitOpError() <<
"port " << getPortName(i)
3045 <<
" has a different type than port " << getPortName(i - 1)
3046 <<
" (expected " << oldDataType <<
", but got " << dataType
3051 oldDataType = dataType;
3054 auto maskWidth = getMaskBits();
3056 auto dataWidth = getDataType().getBitWidthOrSentinel();
3057 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3058 return emitOpError(
"the mask width cannot be greater than "
3061 if (getPortAnnotations().size() != getNumResults())
3062 return emitOpError(
"the number of result annotations should be "
3063 "equal to the number of results");
3069 return std::max(1U, llvm::Log2_64_Ceil(depth));
3075 PortKind portKind,
size_t maskBits) {
3077 auto *context = dataType.getContext();
3078 if (portKind == PortKind::Debug)
3079 return RefType::get(FVectorType::get(dataType, depth));
3085 maskType = UIntType::get(context, maskBits);
3087 auto getId = [&](StringRef name) -> StringAttr {
3088 return StringAttr::get(context, name);
3091 SmallVector<BundleType::BundleElement, 7> portFields;
3095 portFields.push_back({getId(
"addr"),
false, addressType});
3096 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3097 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3100 case PortKind::Read:
3101 portFields.push_back({getId(
"data"),
true, dataType});
3104 case PortKind::Write:
3105 portFields.push_back({getId(
"data"),
false, dataType});
3106 portFields.push_back({getId(
"mask"),
false, maskType});
3109 case PortKind::ReadWrite:
3110 portFields.push_back({getId(
"rdata"),
true, dataType});
3111 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3112 portFields.push_back({getId(
"wdata"),
false, dataType});
3113 portFields.push_back({getId(
"wmask"),
false, maskType});
3116 llvm::report_fatal_error(
"memory port kind not handled");
3120 return BundleType::get(context, portFields);
3124SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3125 SmallVector<MemOp::NamedPort> result;
3127 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3129 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3136MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3138 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3142MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3144 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3148size_t MemOp::getMaskBits() {
3150 for (
auto res : getResults()) {
3151 if (type_isa<RefType>(res.getType()))
3153 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3160 if (t.name.getValue().contains(
"mask"))
3163 if (type_isa<UIntType>(mType))
3173 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3175 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3176 return type_cast<FVectorType>(refType.getType()).getElementType();
3177 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3179 StringRef dataFieldName =
"data";
3181 dataFieldName =
"rdata";
3183 return type_cast<BundleType>(firstPortType.getPassiveType())
3184 .getElementType(dataFieldName);
3187StringAttr MemOp::getPortName(
size_t resultNo) {
3188 return cast<StringAttr>(getPortNames()[resultNo]);
3192 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3195Value MemOp::getPortNamed(StringAttr name) {
3196 auto namesArray = getPortNames();
3197 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3198 if (namesArray[i] == name) {
3199 assert(i < getNumResults() &&
" names array out of sync with results");
3200 return getResult(i);
3209 size_t numReadPorts = 0;
3210 size_t numWritePorts = 0;
3211 size_t numReadWritePorts = 0;
3213 SmallVector<int32_t> writeClockIDs;
3215 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3216 auto portKind = op.getPortKind(i);
3217 if (portKind == MemOp::PortKind::Read)
3219 else if (portKind == MemOp::PortKind::Write) {
3220 for (
auto *a : op.getResult(i).getUsers()) {
3221 auto subfield = dyn_cast<SubfieldOp>(a);
3222 if (!subfield || subfield.getFieldIndex() != 2)
3224 auto clockPort = a->getResult(0);
3225 for (
auto *b : clockPort.getUsers()) {
3226 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3227 if (
connect.getDest() == clockPort) {
3230 connect.getSrc(),
true,
true,
true),
3232 if (result.second) {
3233 writeClockIDs.push_back(numWritePorts);
3235 writeClockIDs.push_back(result.first->second);
3244 ++numReadWritePorts;
3251 op.emitError(
"'firrtl.mem' should have simple type and known width");
3252 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3254 if (op->hasAttr(
"modName"))
3255 modName = op->getAttrOfType<StringAttr>(
"modName");
3257 SmallString<8> clocks;
3258 for (
auto a : writeClockIDs)
3259 clocks.
append(Twine((char)(a +
'a')).str());
3260 SmallString<32> initStr;
3265 for (
auto c : init.getFilename().getValue())
3266 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3267 (c >=
'0' && c <=
'9'))
3268 initStr.push_back(c);
3269 initStr.push_back(
'_');
3270 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3271 initStr.push_back(
'_');
3272 initStr.push_back(init.getIsInline() ?
't' :
'f');
3274 modName = StringAttr::get(
3277 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3278 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3279 numReadWritePorts, (
size_t)width, op.getDepth(),
3280 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3281 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3282 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3284 return {numReadPorts,
3289 op.getReadLatency(),
3290 op.getWriteLatency(),
3292 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3293 seq::WUW::PortOrder,
3296 op.getMaskBits() > 1,
3302void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3307 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3308 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3312std::optional<size_t> MemOp::getTargetResultIndex() {
3314 return std::nullopt;
3322 OpAsmSetValueNameFn setNameFn) {
3325 setNameFn(op.getDataRaw(), name);
3326 if (op.isForceable())
3327 setNameFn(op.getDataRef(), (name +
"_ref").str());
3330void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3334LogicalResult NodeOp::inferReturnTypes(
3335 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3336 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3337 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3338 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3339 if (operands.empty())
3341 Adaptor adaptor(operands, attributes, properties, regions);
3342 inferredReturnTypes.push_back(adaptor.getInput().getType());
3343 if (adaptor.getForceable()) {
3345 true, adaptor.getInput().getType());
3346 if (!forceableType) {
3348 ::mlir::emitError(*location,
"cannot force a node of type ")
3349 << operands[0].getType();
3352 inferredReturnTypes.push_back(forceableType);
3357std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3359void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3363std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3365SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3366RegOp::computeDataFlow() {
3371LogicalResult RegResetOp::verify() {
3372 auto reset = getResetValue();
3379 return emitError(
"type mismatch between register ")
3380 << regType <<
" and reset value " << resetType;
3385std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3387void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3396FormalOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
3398 auto referencedModule = symbolTable.lookupNearestSymbolFrom<FModuleOp>(
3399 *
this, getModuleNameAttr());
3400 if (!referencedModule)
3401 return (*this)->emitOpError(
"invalid symbol reference");
3410void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3414SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3415RegResetOp::computeDataFlow() {
3420std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3422LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3423 auto refType = type_dyn_cast<RefType>(getType(0));
3428 refType, getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3429 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3436void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3438 build(builder, state, klass.getInstanceType(),
3439 StringAttr::get(builder.getContext(), name));
3442LogicalResult ObjectOp::verify() {
return success(); }
3444LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3445 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3446 auto classType = getType();
3447 auto className = classType.getNameAttr();
3450 auto classOp = dyn_cast_or_null<ClassLike>(
3451 symbolTable.lookupSymbolIn(circuitOp, className));
3453 return emitOpError() <<
"references unknown class " << className;
3456 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3462StringAttr ObjectOp::getClassNameAttr() {
3463 return getType().getNameAttr().getAttr();
3466StringRef ObjectOp::getClassName() {
return getType().getName(); }
3468ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3469 auto symRef = getType().getNameAttr();
3470 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3473Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3474 return getReferencedClass(symtbl);
3477StringRef ObjectOp::getInstanceName() {
return getName(); }
3479StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3481StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3483StringAttr ObjectOp::getReferencedModuleNameAttr() {
3484 return getClassNameAttr();
3487void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3488 setNameFn(getResult(),
getName());
3495LogicalResult AttachOp::verify() {
3497 std::optional<int32_t> commonWidth;
3498 for (
auto operand : getOperands()) {
3499 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3503 commonWidth = thisWidth;
3506 if (commonWidth != thisWidth)
3507 return emitOpError(
"is inavlid as not all known operand widths match");
3514 Value dst = connect->getOperand(0);
3515 Value src = connect->getOperand(1);
3526 auto diag = emitError(connect->getLoc());
3527 diag <<
"connect has invalid flow: the source expression ";
3529 diag <<
"\"" << srcName <<
"\" ";
3530 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3531 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3539 auto diag = emitError(connect->getLoc());
3540 diag <<
"connect has invalid flow: the destination expression ";
3542 diag <<
"\"" << dstName <<
"\" ";
3543 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3544 return diag.attachNote(dstRef.getLoc())
3545 <<
"the destination was defined here";
3554 bool outerTypeIsConst =
false) {
3555 auto typeIsConst = outerTypeIsConst || type.
isConst();
3560 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3561 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3562 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3566 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3578 auto dest = connect.getDest();
3579 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3580 auto src = connect.getSrc();
3581 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3582 if (!destType || !srcType)
3585 auto destRefinedType = destType;
3586 auto srcRefinedType = srcType;
3591 auto findFieldDeclarationRefiningFieldType =
3593 while (
auto *definingOp = value.getDefiningOp()) {
3594 bool shouldContinue =
true;
3595 TypeSwitch<Operation *>(definingOp)
3596 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
3597 .Case<SubaccessOp>([&](SubaccessOp op) {
3601 .getElementTypePreservingConst()
3603 originalFieldType = originalFieldType.getConstType(
true);
3604 value = op.getInput();
3606 .Default([&](Operation *) { shouldContinue =
false; });
3607 if (!shouldContinue)
3613 auto destDeclaration =
3614 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
3615 auto srcDeclaration =
3616 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
3618 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
3619 Value declaration) -> LogicalResult {
3620 auto *declarationBlock = declaration.getParentBlock();
3621 auto *block = connect->getBlock();
3622 while (block && block != declarationBlock) {
3623 auto *parentOp = block->getParentOp();
3625 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
3626 whenOp && !whenOp.getCondition().getType().isConst()) {
3628 return connect.emitOpError()
3629 <<
"assignment to 'const' type " << type
3630 <<
" is dependent on a non-'const' condition";
3631 return connect->emitOpError()
3632 <<
"assignment to nested 'const' member of type " << type
3633 <<
" is dependent on a non-'const' condition";
3636 block = parentOp->getBlock();
3641 auto emitSubaccessError = [&] {
3642 return connect.emitError(
3643 "assignment to non-'const' subaccess of 'const' type is disallowed");
3649 if (destType != destRefinedType)
3650 return emitSubaccessError();
3652 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
3657 if (srcRefinedType.containsConst() &&
3660 if (srcType != srcRefinedType)
3661 return emitSubaccessError();
3662 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
3669LogicalResult ConnectOp::verify() {
3670 auto dstType = getDest().getType();
3671 auto srcType = getSrc().getType();
3672 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
3673 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
3674 if (!dstBaseType || !srcBaseType) {
3675 if (dstType != srcType)
3676 return emitError(
"may not connect different non-base types");
3679 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
3680 return emitError(
"analog types may not be connected");
3684 return emitError(
"type mismatch between destination ")
3685 << dstBaseType <<
" and source " << srcBaseType;
3690 return emitError(
"destination ")
3691 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
3704LogicalResult MatchingConnectOp::verify() {
3705 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
3706 auto baseType = type_cast<FIRRTLBaseType>(type);
3709 if (baseType && baseType.containsAnalog())
3710 return emitError(
"analog types may not be connected");
3715 "`SameAnonTypeOperands` trait should have already rejected "
3716 "structurally non-equivalent types");
3729LogicalResult RefDefineOp::verify() {
3739 for (
auto *user : getDest().getUsers()) {
3740 if (
auto conn = dyn_cast<FConnectLike>(user);
3741 conn && conn.getDest() == getDest() && conn != *
this)
3742 return emitError(
"destination reference cannot be reused by multiple "
3743 "operations, it can only capture a unique dataflow");
3747 if (
auto *op = getDest().getDefiningOp()) {
3749 if (isa<RefSubOp>(op))
3751 "destination reference cannot be a sub-element of a reference");
3752 if (isa<RefCastOp>(op))
3754 "destination reference cannot be a cast of another reference");
3762 SmallVector<SymbolRefAttr> missingLayers;
3764 auto diag = emitOpError(
"has more layer requirements than destination");
3765 auto ¬e = diag.attachNote();
3766 note <<
"additional layers required: ";
3767 interleaveComma(missingLayers, note);
3774LogicalResult PropAssignOp::verify() {
3780 for (
auto *user : getDest().getUsers()) {
3781 if (
auto conn = dyn_cast<FConnectLike>(user);
3782 conn && conn.getDest() == getDest() && conn != *
this)
3783 return emitError(
"destination property cannot be reused by multiple "
3784 "operations, it can only capture a unique dataflow");
3790void WhenOp::createElseRegion() {
3791 assert(!hasElseRegion() &&
"already has an else region");
3792 getElseRegion().push_back(
new Block());
3795void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
3796 bool withElseRegion, std::function<
void()> thenCtor,
3797 std::function<
void()> elseCtor) {
3798 OpBuilder::InsertionGuard guard(builder);
3799 result.addOperands(condition);
3802 builder.createBlock(result.addRegion());
3807 Region *elseRegion = result.addRegion();
3808 if (withElseRegion) {
3809 builder.createBlock(elseRegion);
3819LogicalResult MatchOp::verify() {
3820 FEnumType type = getInput().getType();
3823 auto numCases = getTags().size();
3824 auto numRegions = getNumRegions();
3825 if (numRegions != numCases)
3826 return emitOpError(
"expected ")
3827 << numRegions <<
" tags but got " << numCases;
3829 auto numTags = type.getNumElements();
3831 SmallDenseSet<int64_t> seen;
3832 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
3833 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
3836 if (region.getNumArguments() != 1)
3837 return emitOpError(
"region should have exactly one argument");
3840 if (tagIndex >= numTags)
3841 return emitOpError(
"the tag index ")
3842 << tagIndex <<
" is out of the range of valid tags in " << type;
3845 auto [it, inserted] = seen.insert(tagIndex);
3847 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
3848 <<
" is matched more than once";
3851 auto expectedType = type.getElementTypePreservingConst(tagIndex);
3852 auto regionType = region.getArgument(0).getType();
3853 if (regionType != expectedType)
3854 return emitOpError(
"region type ")
3855 << regionType <<
" does not match the expected type "
3860 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
3861 if (!seen.contains(i))
3862 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
3867void MatchOp::print(OpAsmPrinter &p) {
3868 auto input = getInput();
3869 FEnumType type = input.getType();
3870 auto regions = getRegions();
3871 p <<
" " << input <<
" : " << type;
3872 SmallVector<StringRef> elided = {
"tags"};
3873 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
3876 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
3879 p.printKeywordOrString(
3880 type.getElementName(cast<IntegerAttr>(tag).getInt()));
3882 p.printRegionArgument(region.front().getArgument(0), {},
3885 p.printRegion(region,
false);
3892ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
3893 auto *context = parser.getContext();
3894 auto &properties = result.getOrAddProperties<Properties>();
3895 OpAsmParser::UnresolvedOperand input;
3896 if (parser.parseOperand(input) || parser.parseColon())
3899 auto loc = parser.getCurrentLocation();
3901 if (parser.parseType(type))
3903 auto enumType = type_dyn_cast<FEnumType>(type);
3905 return parser.emitError(loc,
"expected enumeration type but got") << type;
3907 if (parser.resolveOperand(input, type, result.operands) ||
3908 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
3909 parser.parseLBrace())
3912 auto i32Type = IntegerType::get(context, 32);
3913 SmallVector<Attribute> tags;
3916 if (failed(parser.parseOptionalKeyword(
"case")))
3920 auto nameLoc = parser.getCurrentLocation();
3922 OpAsmParser::Argument arg;
3923 auto *region = result.addRegion();
3924 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
3925 parser.parseArgument(arg) || parser.parseRParen())
3929 auto index = enumType.getElementIndex(name);
3931 return parser.emitError(nameLoc,
"the tag \"")
3932 << name <<
"\" is not a member of the enumeration " << enumType;
3933 tags.push_back(IntegerAttr::get(i32Type, *index));
3936 arg.type = enumType.getElementTypePreservingConst(*index);
3937 if (parser.parseRegion(*region, arg))
3940 properties.setTags(ArrayAttr::get(context, tags));
3942 return parser.parseRBrace();
3945void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
3947 MutableArrayRef<std::unique_ptr<Region>> regions) {
3948 auto &properties = result.getOrAddProperties<Properties>();
3949 result.addOperands(input);
3950 properties.setTags(tags);
3951 result.addRegions(regions);
3960 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
3961 bool visitInvalidExpr(Operation *op) {
return false; }
3962 bool visitUnhandledExpr(Operation *op) {
return true; }
3968void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3971 if (
auto ty = type_dyn_cast<IntType>(getType())) {
3972 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
3973 auto width = ty.getWidthOrSentinel();
3977 name = (Twine(base) + Twine(width)).str();
3978 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
3979 auto width = ty.getWidthOrSentinel();
3981 name =
"invalid_analog";
3983 name = (
"invalid_analog" + Twine(width)).str();
3984 }
else if (type_isa<AsyncResetType>(getType()))
3985 name =
"invalid_asyncreset";
3986 else if (type_isa<ResetType>(getType()))
3987 name =
"invalid_reset";
3988 else if (type_isa<ClockType>(getType()))
3989 name =
"invalid_clock";
3993 setNameFn(getResult(), name);
3996void ConstantOp::print(OpAsmPrinter &p) {
3998 p.printAttributeWithoutType(getValueAttr());
4000 p.printType(getType());
4001 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4004ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4005 auto &properties = result.getOrAddProperties<Properties>();
4008 auto loc = parser.getCurrentLocation();
4009 auto valueResult = parser.parseOptionalInteger(value);
4010 if (!valueResult.has_value())
4011 return parser.emitError(loc,
"expected integer value");
4015 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4016 parser.parseOptionalAttrDict(result.attributes))
4018 result.addTypes(resultType);
4024 if (width > value.getBitWidth()) {
4028 value = value.sext(width);
4029 }
else if (width < value.getBitWidth()) {
4032 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4033 : value.getActiveBits();
4034 if (width < neededBits)
4035 return parser.emitError(loc,
"constant out of range for result type ")
4037 value = value.trunc(width);
4041 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4043 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4044 properties.setValue(valueAttr);
4048LogicalResult ConstantOp::verify() {
4052 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4054 "firrtl.constant attribute bitwidth doesn't match return type");
4057 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4058 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4059 return emitError(
"firrtl.constant attribute has wrong sign");
4066void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4067 const APInt &value) {
4070 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4071 "incorrect attribute bitwidth for firrtl.constant");
4074 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4075 return build(builder, result, type, attr);
4080void ConstantOp::build(OpBuilder &builder, OperationState &result,
4081 const APSInt &value) {
4082 auto attr = IntegerAttr::get(builder.getContext(), value);
4084 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4085 return build(builder, result, type, attr);
4088void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4095 SmallString<32> specialNameBuffer;
4096 llvm::raw_svector_ostream specialName(specialNameBuffer);
4098 getValue().print(specialName, intTy.
isSigned());
4100 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4103 specialName << width;
4104 setNameFn(getResult(), specialName.str());
4107void SpecialConstantOp::print(OpAsmPrinter &p) {
4110 p << static_cast<unsigned>(getValue());
4112 p.printType(getType());
4113 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4116ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4117 OperationState &result) {
4118 auto &properties = result.getOrAddProperties<Properties>();
4122 auto loc = parser.getCurrentLocation();
4123 auto valueResult = parser.parseOptionalInteger(value);
4124 if (!valueResult.has_value())
4125 return parser.emitError(loc,
"expected integer value");
4128 if (value != 0 && value != 1)
4129 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4133 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4134 parser.parseOptionalAttrDict(result.attributes))
4136 result.addTypes(resultType);
4139 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4140 properties.setValue(valueAttr);
4144void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4145 SmallString<32> specialNameBuffer;
4146 llvm::raw_svector_ostream specialName(specialNameBuffer);
4148 specialName << static_cast<unsigned>(getValue());
4149 auto type = getType();
4150 if (type_isa<ClockType>(type)) {
4151 specialName <<
"_clock";
4152 }
else if (type_isa<ResetType>(type)) {
4153 specialName <<
"_reset";
4154 }
else if (type_isa<AsyncResetType>(type)) {
4155 specialName <<
"_asyncreset";
4157 setNameFn(getResult(), specialName.str());
4164 if (type.isGround()) {
4165 if (!isa<IntegerAttr>(attr)) {
4166 op->emitOpError(
"Ground type is not an integer attribute");
4171 auto attrlist = dyn_cast<ArrayAttr>(attr);
4173 op->emitOpError(
"expected array attribute for aggregate constant");
4176 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4177 if (array.getNumElements() != attrlist.size()) {
4178 op->emitOpError(
"array attribute (")
4179 << attrlist.size() <<
") has wrong size for vector constant ("
4180 << array.getNumElements() <<
")";
4183 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4187 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4188 if (bundle.getNumElements() != attrlist.size()) {
4189 op->emitOpError(
"array attribute (")
4190 << attrlist.size() <<
") has wrong size for bundle constant ("
4191 << bundle.getNumElements() <<
")";
4194 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4195 if (bundle.getElement(i).isFlip) {
4196 op->emitOpError(
"Cannot have constant bundle type with flip");
4204 op->emitOpError(
"Unknown aggregate type");
4208LogicalResult AggregateConstantOp::verify() {
4214Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4216 Attribute value = getFields();
4217 while (fieldID != 0) {
4218 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4219 auto index = bundle.getIndexForFieldID(fieldID);
4220 fieldID -= bundle.getFieldID(index);
4221 type = bundle.getElementType(index);
4222 value = cast<ArrayAttr>(value)[index];
4224 auto vector = type_cast<FVectorType>(type);
4225 auto index = vector.getIndexForFieldID(fieldID);
4226 fieldID -= vector.getFieldID(index);
4227 type = vector.getElementType();
4228 value = cast<ArrayAttr>(value)[index];
4234void FIntegerConstantOp::print(OpAsmPrinter &p) {
4236 p.printAttributeWithoutType(getValueAttr());
4237 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4240ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4241 OperationState &result) {
4242 auto *context = parser.getContext();
4243 auto &properties = result.getOrAddProperties<Properties>();
4245 if (parser.parseInteger(value) ||
4246 parser.parseOptionalAttrDict(result.attributes))
4248 result.addTypes(FIntegerType::get(context));
4250 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4251 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4252 properties.setValue(valueAttr);
4256ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4257 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4260 if (parser.parseOperandList(operands) ||
4261 parser.parseOptionalAttrDict(result.attributes) ||
4262 parser.parseColonType(type))
4264 result.addTypes(type);
4266 return parser.resolveOperands(operands, type.getElementType(),
4270void ListCreateOp::print(OpAsmPrinter &p) {
4272 p.printOperands(getElements());
4273 p.printOptionalAttrDict((*this)->getAttrs());
4274 p <<
" : " << getType();
4277LogicalResult ListCreateOp::verify() {
4278 if (getElements().
empty())
4281 auto elementType = getElements().front().getType();
4282 auto listElementType = getType().getElementType();
4284 return emitOpError(
"has elements of type ")
4285 <<
elementType <<
" instead of " << listElementType;
4290LogicalResult BundleCreateOp::verify() {
4291 BundleType resultType = getType();
4292 if (resultType.getNumElements() != getFields().size())
4293 return emitOpError(
"number of fields doesn't match type");
4294 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4296 resultType.getElementTypePreservingConst(i),
4297 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4298 return emitOpError(
"type of element doesn't match bundle for field ")
4299 << resultType.getElement(i).name;
4304LogicalResult VectorCreateOp::verify() {
4305 FVectorType resultType = getType();
4306 if (resultType.getNumElements() != getFields().size())
4307 return emitOpError(
"number of fields doesn't match type");
4308 auto elemTy = resultType.getElementTypePreservingConst();
4309 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4311 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4312 return emitOpError(
"type of element doesn't match vector element");
4321LogicalResult FEnumCreateOp::verify() {
4322 FEnumType resultType = getResult().getType();
4323 auto elementIndex = resultType.getElementIndex(
getFieldName());
4325 return emitOpError(
"label ")
4326 <<
getFieldName() <<
" is not a member of the enumeration type "
4329 resultType.getElementTypePreservingConst(*elementIndex),
4330 getInput().getType()))
4331 return emitOpError(
"type of element doesn't match enum element");
4335void FEnumCreateOp::print(OpAsmPrinter &printer) {
4338 printer <<
'(' << getInput() <<
')';
4339 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4340 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4342 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4343 ArrayRef<Type>{getResult().getType()});
4346ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4347 auto *context = parser.getContext();
4348 auto &properties = result.getOrAddProperties<Properties>();
4350 OpAsmParser::UnresolvedOperand input;
4351 std::string fieldName;
4352 mlir::FunctionType functionType;
4353 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4354 parser.parseOperand(input) || parser.parseRParen() ||
4355 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4356 parser.parseType(functionType))
4359 if (functionType.getNumInputs() != 1)
4360 return parser.emitError(parser.getNameLoc(),
"single input type required");
4361 if (functionType.getNumResults() != 1)
4362 return parser.emitError(parser.getNameLoc(),
"single result type required");
4364 auto inputType = functionType.getInput(0);
4365 if (parser.resolveOperand(input, inputType, result.operands))
4368 auto outputType = functionType.getResult(0);
4369 auto enumType = type_dyn_cast<FEnumType>(outputType);
4371 return parser.emitError(parser.getNameLoc(),
4372 "output must be enum type, got ")
4374 auto fieldIndex = enumType.getElementIndex(fieldName);
4376 return parser.emitError(parser.getNameLoc(),
4377 "unknown field " + fieldName +
" in enum type ")
4380 properties.setFieldIndex(
4381 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4383 result.addTypes(enumType);
4392LogicalResult IsTagOp::verify() {
4393 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4394 return emitOpError(
"element index is greater than the number of fields in "
4399void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4400 printer <<
' ' << getInput() <<
' ';
4402 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4403 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4404 printer <<
" : " << getInput().getType();
4407ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4408 auto *context = parser.getContext();
4409 auto &properties = result.getOrAddProperties<Properties>();
4411 OpAsmParser::UnresolvedOperand input;
4412 std::string fieldName;
4414 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4415 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4416 parser.parseType(inputType))
4419 if (parser.resolveOperand(input, inputType, result.operands))
4422 auto enumType = type_dyn_cast<FEnumType>(inputType);
4424 return parser.emitError(parser.getNameLoc(),
4425 "input must be enum type, got ")
4427 auto fieldIndex = enumType.getElementIndex(fieldName);
4429 return parser.emitError(parser.getNameLoc(),
4430 "unknown field " + fieldName +
" in enum type ")
4433 properties.setFieldIndex(
4434 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4436 result.addTypes(UIntType::get(context, 1,
false));
4441FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4442 OpaqueProperties properties,
4443 mlir::RegionRange regions,
4444 std::optional<Location> loc) {
4445 Adaptor adaptor(operands, attrs, properties, regions);
4446 return UIntType::get(attrs.getContext(), 1,
4447 isConst(adaptor.getInput().getType()));
4450template <
typename OpTy>
4452 auto *context = parser.getContext();
4454 OpAsmParser::UnresolvedOperand input;
4455 std::string fieldName;
4457 if (parser.parseOperand(input) || parser.parseLSquare() ||
4458 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4459 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4460 parser.parseType(inputType))
4463 if (parser.resolveOperand(input, inputType, result.operands))
4466 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4468 return parser.emitError(parser.getNameLoc(),
4469 "input must be bundle type, got ")
4471 auto fieldIndex = bundleType.getElementIndex(fieldName);
4473 return parser.emitError(parser.getNameLoc(),
4474 "unknown field " + fieldName +
" in bundle type ")
4477 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4478 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4480 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4483 result.addTypes(type);
4488ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4489 auto *context = parser.getContext();
4491 OpAsmParser::UnresolvedOperand input;
4492 std::string fieldName;
4494 if (parser.parseOperand(input) || parser.parseLSquare() ||
4495 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4496 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4497 parser.parseType(inputType))
4500 if (parser.resolveOperand(input, inputType, result.operands))
4503 auto enumType = type_dyn_cast<FEnumType>(inputType);
4505 return parser.emitError(parser.getNameLoc(),
4506 "input must be enum type, got ")
4508 auto fieldIndex = enumType.getElementIndex(fieldName);
4510 return parser.emitError(parser.getNameLoc(),
4511 "unknown field " + fieldName +
" in enum type ")
4514 result.getOrAddProperties<Properties>().setFieldIndex(
4515 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4517 SmallVector<Type> inferredReturnTypes;
4518 if (failed(SubtagOp::inferReturnTypes(
4519 context, result.location, result.operands,
4520 result.attributes.getDictionary(context), result.getRawProperties(),
4521 result.regions, inferredReturnTypes)))
4523 result.addTypes(inferredReturnTypes);
4528ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4529 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4531ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4532 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4535template <
typename OpTy>
4537 printer <<
' ' << op.getInput() <<
'[';
4538 printer.printKeywordOrString(op.getFieldName());
4540 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4541 elidedAttrs.push_back(
"fieldIndex");
4542 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4543 printer <<
" : " << op.getInput().getType();
4545void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4546 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4548void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4549 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4552void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4553 printer <<
' ' << getInput() <<
'[';
4556 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4557 elidedAttrs.push_back(
"fieldIndex");
4558 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4559 printer <<
" : " << getInput().getType();
4562template <
typename OpTy>
4564 if (op.getFieldIndex() >=
4565 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4567 return op.emitOpError(
"subfield element index is greater than the number "
4568 "of fields in the bundle type");
4571LogicalResult SubfieldOp::verify() {
4572 return verifySubfieldLike<SubfieldOp>(*
this);
4574LogicalResult OpenSubfieldOp::verify() {
4575 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4578LogicalResult SubtagOp::verify() {
4579 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4580 return emitOpError(
"subfield element index is greater than the number "
4581 "of fields in the bundle type");
4591 SmallVector<Operation *, 8> worklist({op});
4595 bool constant =
true;
4601 while (constant && !(worklist.empty()))
4602 TypeSwitch<Operation *>(worklist.pop_back_val())
4603 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
4604 if (
auto definingOp = op.getInput().getDefiningOp())
4605 worklist.push_back(definingOp);
4608 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
4609 for (
auto &use : op.getResult().getUses())
4610 worklist.push_back(use.getOwner());
4612 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
4613 .Default([&](
auto) { constant =
false; });
4622 if (
auto *op = value.getDefiningOp())
4627LogicalResult ConstCastOp::verify() {
4629 return emitOpError() << getInput().getType()
4630 <<
" is not 'const'-castable to "
4631 << getResult().getType();
4635FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4636 std::optional<Location> loc) {
4637 auto inType = type_cast<BundleType>(type);
4639 if (fieldIndex >= inType.getNumElements())
4641 "subfield element index is greater than the "
4642 "number of fields in the bundle type");
4646 return inType.getElementTypePreservingConst(fieldIndex);
4649FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
4650 std::optional<Location> loc) {
4651 auto inType = type_cast<OpenBundleType>(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);
4663bool SubfieldOp::isFieldFlipped() {
4664 BundleType bundle = getInput().getType();
4665 return bundle.getElement(getFieldIndex()).isFlip;
4667bool OpenSubfieldOp::isFieldFlipped() {
4668 auto bundle = getInput().getType();
4669 return bundle.getElement(getFieldIndex()).isFlip;
4672FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4673 std::optional<Location> loc) {
4674 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
4675 if (fieldIndex < vectorType.getNumElements())
4676 return vectorType.getElementTypePreservingConst();
4678 "' in vector type ", type);
4683FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
4684 std::optional<Location> loc) {
4685 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
4686 if (fieldIndex < vectorType.getNumElements())
4687 return vectorType.getElementTypePreservingConst();
4689 "' in vector type ", type);
4695FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4696 OpaqueProperties properties,
4697 mlir::RegionRange regions,
4698 std::optional<Location> loc) {
4699 Adaptor adaptor(operands, attrs, properties, regions);
4700 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4701 auto fieldIndex = adaptor.getFieldIndex();
4703 if (fieldIndex >= inType.getNumElements())
4705 "subtag element index is greater than the "
4706 "number of fields in the enum type");
4710 auto elementType = inType.getElement(fieldIndex).type;
4714FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
4715 std::optional<Location> loc) {
4716 if (!type_isa<UIntType>(indexType))
4720 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
4722 return vectorType.getElementTypePreservingConst();
4723 return vectorType.getElementType().getAllConstDroppedType();
4730FIRRTLType TagExtractOp::inferReturnType(ValueRange operands,
4731 DictionaryAttr attrs,
4732 OpaqueProperties properties,
4733 mlir::RegionRange regions,
4734 std::optional<Location> loc) {
4735 Adaptor adaptor(operands, attrs, properties, regions);
4736 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
4737 auto i = llvm::Log2_32_Ceil(inType.getNumElements());
4738 return UIntType::get(inType.getContext(), i);
4741ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
4742 OpAsmParser::UnresolvedOperand index;
4743 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
4744 Type indexType, elemType;
4746 if (parser.parseOperand(index) || parser.parseComma() ||
4747 parser.parseOperandList(inputs) ||
4748 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4749 parser.parseType(indexType) || parser.parseComma() ||
4750 parser.parseType(elemType))
4753 if (parser.resolveOperand(index, indexType, result.operands))
4756 result.addTypes(elemType);
4758 return parser.resolveOperands(inputs, elemType, result.operands);
4761void MultibitMuxOp::print(OpAsmPrinter &p) {
4762 p <<
" " << getIndex() <<
", ";
4763 p.printOperands(getInputs());
4764 p.printOptionalAttrDict((*this)->getAttrs());
4765 p <<
" : " << getIndex().getType() <<
", " << getType();
4768FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
4769 DictionaryAttr attrs,
4770 OpaqueProperties properties,
4771 mlir::RegionRange regions,
4772 std::optional<Location> loc) {
4773 if (operands.size() < 2)
4777 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
4778 return operands[1].getType() == op.getType();
4782 return type_cast<FIRRTLType>(operands[1].getType());
4789LogicalResult ObjectSubfieldOp::inferReturnTypes(
4790 MLIRContext *context, std::optional<mlir::Location> location,
4791 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
4792 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
4794 inferReturnType(operands, attributes, properties, regions, location);
4797 inferredReturnTypes.push_back(type);
4801Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
4802 std::optional<Location> loc) {
4803 auto classType = dyn_cast<ClassType>(inType);
4807 if (classType.getNumElements() <= fieldIndex)
4809 "number of fields in the object");
4810 return classType.getElement(fieldIndex).type;
4813void ObjectSubfieldOp::print(OpAsmPrinter &p) {
4814 auto input = getInput();
4815 auto classType = input.getType();
4816 p <<
' ' << input <<
"[";
4817 p.printKeywordOrString(classType.getElement(getIndex()).name);
4819 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
4820 p <<
" : " << classType;
4823ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
4824 OperationState &result) {
4825 auto *context = parser.getContext();
4827 OpAsmParser::UnresolvedOperand input;
4828 std::string fieldName;
4829 ClassType inputType;
4830 if (parser.parseOperand(input) || parser.parseLSquare() ||
4831 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4832 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4833 parser.parseType(inputType) ||
4834 parser.resolveOperand(input, inputType, result.operands))
4837 auto index = inputType.getElementIndex(fieldName);
4839 return parser.emitError(parser.getNameLoc(),
4840 "unknown field " + fieldName +
" in class type ")
4842 result.getOrAddProperties<Properties>().setIndex(
4843 IntegerAttr::get(IntegerType::get(context, 32), *index));
4845 SmallVector<Type> inferredReturnTypes;
4846 if (failed(inferReturnTypes(context, result.location, result.operands,
4847 result.attributes.getDictionary(context),
4848 result.getRawProperties(), result.regions,
4849 inferredReturnTypes)))
4851 result.addTypes(inferredReturnTypes);
4868 int32_t &rhsWidth,
bool &isConstResult,
4869 std::optional<Location> loc) {
4871 auto lhsi = type_dyn_cast<IntType>(lhs);
4872 auto rhsi = type_dyn_cast<IntType>(rhs);
4873 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
4876 mlir::emitError(*loc,
"second operand must be an integer type, not ")
4878 else if (!lhsi && rhsi)
4879 mlir::emitError(*loc,
"first operand must be an integer type, not ")
4881 else if (!lhsi && !rhsi)
4882 mlir::emitError(*loc,
"operands must be integer types, not ")
4883 << lhs <<
" and " << rhs;
4885 mlir::emitError(*loc,
"operand signedness must match");
4890 lhsWidth = lhsi.getWidthOrSentinel();
4891 rhsWidth = rhsi.getWidthOrSentinel();
4892 isConstResult = lhsi.isConst() && rhsi.isConst();
4897 assert(op->getNumOperands() == 2 &&
4898 "SameOperandsIntTypeKind on non-binary op");
4899 int32_t lhsWidth, rhsWidth;
4902 op->getOperand(1).getType(), lhsWidth,
4903 rhsWidth, isConstResult, op->getLoc()));
4907 std::optional<Location> loc) {
4908 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4909 bool isConstResult =
false;
4913 if (lhsWidth != -1 && rhsWidth != -1)
4914 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
4915 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4920 std::optional<Location> loc) {
4921 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4922 bool isConstResult =
false;
4926 if (lhsWidth != -1 && rhsWidth != -1)
4927 resultWidth = lhsWidth + rhsWidth;
4929 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4934 std::optional<Location> loc) {
4935 int32_t lhsWidth, rhsWidth;
4936 bool isConstResult =
false;
4941 if (type_isa<UIntType>(lhs))
4942 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
4945 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
4946 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
4950 std::optional<Location> loc) {
4951 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4952 bool isConstResult =
false;
4956 if (lhsWidth != -1 && rhsWidth != -1)
4957 resultWidth = std::min(lhsWidth, rhsWidth);
4958 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
4963 std::optional<Location> loc) {
4964 int32_t lhsWidth, rhsWidth, resultWidth = -1;
4965 bool isConstResult =
false;
4969 if (lhsWidth != -1 && rhsWidth != -1) {
4970 resultWidth = std::max(lhsWidth, rhsWidth);
4971 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
4974 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
4978 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
4982 std::optional<Location> loc) {
4983 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
4986 auto lhsVec = type_cast<FVectorType>(lhs);
4987 auto rhsVec = type_cast<FVectorType>(rhs);
4989 if (lhsVec.getNumElements() != rhsVec.getNumElements())
4994 rhsVec.getElementTypePreservingConst(), loc);
4997 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
4998 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
4999 lhsVec.isConst() && rhsVec.isConst() &&
5000 elemBaseType.isConst());
5004 std::optional<Location> loc) {
5005 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5009 std::optional<Location> loc) {
5010 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5011 bool isConstResult =
false;
5015 if (lhsWidth != -1 && rhsWidth != -1)
5016 resultWidth = lhsWidth + rhsWidth;
5017 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5021 std::optional<Location> loc) {
5022 auto lhsi = type_dyn_cast<IntType>(lhs);
5023 auto rhsui = type_dyn_cast<UIntType>(rhs);
5024 if (!rhsui || !lhsi)
5026 loc,
"first operand should be integer, second unsigned int");
5030 auto width = lhsi.getWidthOrSentinel();
5031 if (width == -1 || !rhsui.getWidth().has_value()) {
5034 auto amount = *rhsui.getWidth();
5037 "shift amount too large: second operand of "
5038 "dshl is wider than 31 bits");
5039 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5040 if (newWidth > INT32_MAX)
5042 loc,
"shift amount too large: first operand shifted by maximum "
5043 "amount exceeds maximum width");
5046 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5047 lhsi.
isConst() && rhsui.isConst());
5051 std::optional<Location> loc) {
5052 auto lhsi = type_dyn_cast<IntType>(lhs);
5053 auto rhsu = type_dyn_cast<UIntType>(rhs);
5056 loc,
"first operand should be integer, second unsigned int");
5057 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5061 std::optional<Location> loc) {
5062 auto lhsi = type_dyn_cast<IntType>(lhs);
5063 auto rhsu = type_dyn_cast<UIntType>(rhs);
5066 loc,
"first operand should be integer, second unsigned int");
5067 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5075 std::optional<Location> loc) {
5076 return UIntType::get(input.getContext(), 32);
5080 std::optional<Location> loc) {
5081 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5084 int32_t width = base.getBitWidthOrSentinel();
5087 return SIntType::get(input.getContext(), width, base.
isConst());
5091 std::optional<Location> loc) {
5092 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5095 int32_t width = base.getBitWidthOrSentinel();
5098 return UIntType::get(input.getContext(), width, base.
isConst());
5102 std::optional<Location> loc) {
5103 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5106 "operand must be single bit scalar base type");
5107 int32_t width = base.getBitWidthOrSentinel();
5108 if (width == -2 || width == 0 || width > 1)
5110 return AsyncResetType::get(input.getContext(), base.
isConst());
5114 std::optional<Location> loc) {
5115 return ClockType::get(input.getContext(),
isConst(input));
5119 std::optional<Location> loc) {
5120 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5121 auto width = uiType.getWidthOrSentinel();
5124 return SIntType::get(input.getContext(), width, uiType.
isConst());
5127 if (type_isa<SIntType>(input))
5134 std::optional<Location> loc) {
5135 auto inputi = type_dyn_cast<IntType>(input);
5138 int32_t width = inputi.getWidthOrSentinel();
5141 return SIntType::get(input.getContext(), width, inputi.
isConst());
5145 std::optional<Location> loc) {
5146 auto inputi = type_dyn_cast<IntType>(input);
5149 if (isa<UIntType>(inputi))
5151 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5156 std::optional<Location> loc) {
5157 return UIntType::get(input.getContext(), 1,
isConst(input));
5166 std::optional<Location> loc) {
5167 auto inputi = type_dyn_cast<IntType>(input);
5170 loc,
"input type should be the int type but got ", input);
5175 loc,
"high must be equal or greater than low, but got high = ", high,
5183 int32_t width = inputi.getWidthOrSentinel();
5184 if (width != -1 && high >= width)
5187 "high must be smaller than the width of input, but got high = ", high,
5188 ", width = ", width);
5190 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5194 std::optional<Location> loc) {
5196 auto inputi = type_dyn_cast<IntType>(input);
5197 if (amount < 0 || !inputi)
5199 loc,
"operand must have integer type and amount must be >= 0");
5201 int32_t width = inputi.getWidthOrSentinel();
5202 if (width != -1 && amount > width)
5205 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5220 bool isConstCondition,
5221 std::optional<Location> loc) {
5227 if (high.getTypeID() != low.getTypeID())
5228 return emitInferRetTypeError<FIRRTLBaseType>(
5229 loc,
"incompatible mux operand types, true value type: ", high,
5230 ", false value type: ", low);
5232 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5237 if (type_isa<IntType>(low)) {
5242 if (highWidth == -1)
5244 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5248 auto highVector = type_dyn_cast<FVectorType>(high);
5249 auto lowVector = type_dyn_cast<FVectorType>(low);
5250 if (highVector && lowVector &&
5251 highVector.getNumElements() == lowVector.getNumElements()) {
5253 lowVector.getElementTypePreservingConst(),
5254 isConstCondition, loc);
5257 return FVectorType::get(inner, lowVector.getNumElements(),
5262 auto highBundle = type_dyn_cast<BundleType>(high);
5263 auto lowBundle = type_dyn_cast<BundleType>(low);
5264 if (highBundle && lowBundle) {
5265 auto highElements = highBundle.getElements();
5266 auto lowElements = lowBundle.getElements();
5269 SmallVector<BundleType::BundleElement> newElements;
5271 bool failed =
false;
5273 if (highElements[i].name != lowElements[i].name ||
5274 highElements[i].isFlip != lowElements[i].isFlip) {
5278 auto element = highElements[i];
5280 highBundle.getElementTypePreservingConst(i),
5281 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5284 newElements.push_back(element);
5287 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5289 return emitInferRetTypeError<FIRRTLBaseType>(
5290 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5291 ", false value type: ", low);
5296 return emitInferRetTypeError<FIRRTLBaseType>(
5297 loc,
"invalid mux operand types, true value type: ", high,
5298 ", false value type: ", low);
5303 std::optional<Location> loc) {
5304 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5305 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5306 if (!highType || !lowType)
5311FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5312 DictionaryAttr attrs,
5313 OpaqueProperties properties,
5314 mlir::RegionRange regions,
5315 std::optional<Location> loc) {
5316 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5317 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5318 if (!highType || !lowType)
5324FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5325 DictionaryAttr attrs,
5326 OpaqueProperties properties,
5327 mlir::RegionRange regions,
5328 std::optional<Location> loc) {
5329 SmallVector<FIRRTLBaseType> types;
5331 for (
unsigned i = 1; i < 5; i++) {
5332 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5337 isConst(operands[0].getType()), loc);
5341 result = types.back();
5348 std::optional<Location> loc) {
5349 auto inputi = type_dyn_cast<IntType>(input);
5350 if (amount < 0 || !inputi)
5352 loc,
"pad input must be integer and amount must be >= 0");
5354 int32_t width = inputi.getWidthOrSentinel();
5358 width = std::max<int32_t>(width, amount);
5359 return IntType::get(input.getContext(), inputi.isSigned(), width,
5364 std::optional<Location> loc) {
5365 auto inputi = type_dyn_cast<IntType>(input);
5366 if (amount < 0 || !inputi)
5368 loc,
"shl input must be integer and amount must be >= 0");
5370 int32_t width = inputi.getWidthOrSentinel();
5374 return IntType::get(input.getContext(), inputi.isSigned(), width,
5379 std::optional<Location> loc) {
5380 auto inputi = type_dyn_cast<IntType>(input);
5381 if (amount < 0 || !inputi)
5383 loc,
"shr input must be integer and amount must be >= 0");
5385 int32_t width = inputi.getWidthOrSentinel();
5388 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5389 width = std::max<int32_t>(minWidth, width - amount);
5392 return IntType::get(input.getContext(), inputi.isSigned(), width,
5397 std::optional<Location> loc) {
5399 auto inputi = type_dyn_cast<IntType>(input);
5400 if (amount < 0 || !inputi)
5402 loc,
"tail input must be integer and amount must be >= 0");
5404 int32_t width = inputi.getWidthOrSentinel();
5408 loc,
"amount must be less than or equal operand width");
5419void VerbatimExprOp::getAsmResultNames(
5420 function_ref<
void(Value, StringRef)> setNameFn) {
5424 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5425 auto name = getText();
5427 if (name.starts_with(
"`"))
5428 name = name.drop_front();
5429 name = name.take_while(isOkCharacter);
5431 setNameFn(getResult(), name);
5438void VerbatimWireOp::getAsmResultNames(
5439 function_ref<
void(Value, StringRef)> setNameFn) {
5443 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5444 auto name = getText();
5446 if (name.starts_with(
"`"))
5447 name = name.drop_front();
5448 name = name.take_while(isOkCharacter);
5450 setNameFn(getResult(), name);
5461 op->emitError() <<
"unknown width is not allowed for DPI";
5462 return WalkResult::interrupt();
5464 if (width == 1 || width == 8 || width == 16 || width == 32 ||
5466 return WalkResult::advance();
5468 <<
"integer types used by DPI functions must have a "
5469 "specific bit width; "
5470 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5471 "32(int), 64(longint) "
5472 "or greater than 64, but got "
5474 return WalkResult::interrupt();
5479LogicalResult DPICallIntrinsicOp::verify() {
5480 if (
auto inputNames = getInputNames()) {
5481 if (getInputs().size() != inputNames->size())
5482 return emitError() <<
"inputNames has " << inputNames->size()
5483 <<
" elements but there are " << getInputs().size()
5484 <<
" input arguments";
5486 if (
auto outputName = getOutputName())
5487 if (getNumResults() == 0)
5488 return emitError() <<
"output name is given but there is no result";
5490 auto checkType = [
this](Type type) {
5493 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5494 llvm::all_of(this->getOperandTypes(), checkType));
5497SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5498DPICallIntrinsicOp::computeDataFlow() {
5502 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5504 for (
auto operand : getOperands()) {
5505 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5507 SmallVector<circt::FieldRef> operandFields;
5510 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5514 for (
auto result : getResults())
5517 for (
auto field : operandFields)
5518 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
5528LogicalResult HWStructCastOp::verify() {
5530 BundleType bundleType;
5531 hw::StructType structType;
5532 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5533 structType = dyn_cast<hw::StructType>(getType());
5535 return emitError(
"result type must be a struct");
5536 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5537 structType = dyn_cast<hw::StructType>(getOperand().getType());
5539 return emitError(
"operand type must be a struct");
5541 return emitError(
"either source or result type must be a bundle type");
5544 auto firFields = bundleType.getElements();
5545 auto hwFields = structType.getElements();
5546 if (firFields.size() != hwFields.size())
5547 return emitError(
"bundle and struct have different number of fields");
5549 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
5550 if (firFields[findex].name.getValue() != hwFields[findex].name)
5551 return emitError(
"field names don't match '")
5552 << firFields[findex].name.getValue() <<
"', '"
5553 << hwFields[findex].name.getValue() <<
"'";
5557 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
5558 return emitError(
"size of field '")
5559 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
5566LogicalResult BitCastOp::verify() {
5567 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
5569 if (inTypeBits.has_value() && resTypeBits.has_value()) {
5571 if (*inTypeBits == *resTypeBits) {
5574 return emitError(
"cannot cast non-'const' input type ")
5575 << getOperand().getType() <<
" to 'const' result type "
5579 return emitError(
"the bitwidth of input (")
5580 << *inTypeBits <<
") and result (" << *resTypeBits
5583 if (!inTypeBits.has_value())
5584 return emitError(
"bitwidth cannot be determined for input operand type ")
5585 << getInput().getType();
5586 return emitError(
"bitwidth cannot be determined for result type ")
5597 NamedAttrList &resultAttrs) {
5598 auto result = parser.parseOptionalAttrDict(resultAttrs);
5599 if (!resultAttrs.get(
"annotations"))
5600 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
5606 DictionaryAttr attr,
5607 ArrayRef<StringRef> extraElides = {}) {
5608 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
5610 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
5611 elidedAttrs.push_back(
"annotations");
5613 elidedAttrs.push_back(
"nameKind");
5615 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
5621 NamedAttrList &resultAttrs) {
5624 if (!resultAttrs.get(
"portAnnotations")) {
5625 SmallVector<Attribute, 16> portAnnotations(
5626 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
5627 resultAttrs.append(
"portAnnotations",
5628 parser.getBuilder().getArrayAttr(portAnnotations));
5635 DictionaryAttr attr,
5636 ArrayRef<StringRef> extraElides = {}) {
5637 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
5639 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
5640 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
5641 elidedAttrs.push_back(
"portAnnotations");
5650 firrtl::NameKindEnumAttr &result) {
5653 if (!parser.parseOptionalKeyword(&keyword,
5654 {
"interesting_name",
"droppable_name"})) {
5655 auto kind = symbolizeNameKindEnum(keyword);
5656 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
5662 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
5667 firrtl::NameKindEnumAttr attr,
5668 ArrayRef<StringRef> extraElides = {}) {
5669 if (attr.getValue() != NameKindEnum::DroppableName)
5670 p <<
" " << stringifyNameKindEnum(attr.getValue());
5678 NamedAttrList &resultAttrs) {
5686 DictionaryAttr attrs) {
5687 SmallVector<StringRef, 4> elides;
5689 elides.push_back(Forceable::getForceableAttrName());
5698static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
5703static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
5714 if (ClassType::parseInterface(parser, type))
5721 type.printInterface(p);
5729 NamedAttrList &resultAttrs) {
5730 auto result = p.parseOptionalAttrDict(resultAttrs);
5731 if (!resultAttrs.get(
"name"))
5732 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
5738 DictionaryAttr attr,
5739 ArrayRef<StringRef> extraElides = {}) {
5740 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
5741 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
5742 elides.push_back(
"name");
5744 p.printOptionalAttrDict(op->getAttrs(), elides);
5748 NamedAttrList &resultAttrs) {
5753 DictionaryAttr attr) {
5762 DictionaryAttr attr) {
5771 DictionaryAttr attr) {
5780 OpAsmSetValueNameFn setNameFn) {
5783 if (op->getNumResults() == 1)
5784 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
5785 setNameFn(op->getResult(0), nameAttr.getValue());
5788void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5792void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5796void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5800void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5803void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5806void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5809void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5812void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5815void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5818void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5821void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5824void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5827void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5830void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5833void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5836void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5839void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5842void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5845void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5848void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5851void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5854void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5857void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5860void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5863void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5866void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5869void PlusArgsValueIntrinsicOp::getAsmResultNames(
5870 OpAsmSetValueNameFn setNameFn) {
5873void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5876void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5879void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5882void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5885void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5888void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5891void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5894void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5897void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5900void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5903void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5906void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5909void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5912void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5915void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5918void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5921void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5925void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5929void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5933void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5937void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5941void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5945void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5949void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5953void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5957void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5961void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5965void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5969void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5973void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5977void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5981void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5985void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5993void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
5997void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6001void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6005void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6009void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6013FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6014 DictionaryAttr attrs,
6015 OpaqueProperties properties,
6016 mlir::RegionRange regions,
6017 std::optional<Location> loc) {
6018 Type inType = operands[0].getType();
6019 auto inRefType = type_dyn_cast<RefType>(inType);
6022 loc,
"ref.resolve operand must be ref type, not ", inType);
6023 return inRefType.getType();
6026FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6027 OpaqueProperties properties,
6028 mlir::RegionRange regions,
6029 std::optional<Location> loc) {
6030 Type inType = operands[0].getType();
6031 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6034 loc,
"ref.send operand must be base type, not ", inType);
6035 return RefType::get(inBaseType.getPassiveType());
6038FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6039 std::optional<Location> loc) {
6040 auto refType = type_dyn_cast<RefType>(type);
6043 auto inType = refType.getType();
6049 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6050 if (fieldIndex < vectorType.getNumElements())
6051 return RefType::get(
6052 vectorType.getElementType().getConstType(
6053 vectorType.isConst() || vectorType.getElementType().isConst()),
6054 refType.getForceable(), refType.getLayer());
6056 "' in RefType of vector type ", refType);
6058 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6059 if (fieldIndex >= bundleType.getNumElements()) {
6061 "subfield element index is greater than "
6062 "the number of fields in the bundle type");
6064 return RefType::get(
6065 bundleType.getElement(fieldIndex)
6067 bundleType.isConst() ||
6068 bundleType.getElement(fieldIndex).type.isConst()),
6069 refType.getForceable(), refType.getLayer());
6073 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6076LogicalResult RefCastOp::verify() {
6079 SmallVector<SymbolRefAttr> missingLayers;
6082 emitOpError(
"cannot discard layer requirements of input reference");
6083 auto ¬e = diag.attachNote();
6084 note <<
"discarding layer requirements: ";
6085 llvm::interleaveComma(missingLayers, note);
6091LogicalResult RefResolveOp::verify() {
6094 SmallVector<SymbolRefAttr> missingLayers;
6097 emitOpError(
"ambient layers are insufficient to resolve reference");
6098 auto ¬e = diag.attachNote();
6099 note <<
"missing layer requirements: ";
6100 interleaveComma(missingLayers, note);
6107 auto targetRef = getTarget();
6108 if (targetRef.getModule() !=
6109 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6110 return emitOpError() <<
"has non-local target";
6112 auto target = ns.
lookup(targetRef);
6114 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6116 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6121 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6122 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6123 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6124 << fType <<
" instead of expected " << getType().getType();
6125 diag.attachNote(loc) <<
"target resolves here";
6131 auto checkLayers = [&](Location loc) -> LogicalResult {
6134 SmallVector<SymbolRefAttr> missingLayers;
6136 auto diag = emitOpError(
"target has insufficient layer requirements");
6137 auto ¬e = diag.attachNote(loc);
6138 note <<
"target is missing layer requirements: ";
6139 llvm::interleaveComma(missingLayers, note);
6144 auto checks = [&](
auto type, Location loc) {
6145 if (failed(checkLayers(loc)))
6147 return checkFinalType(type, loc);
6150 if (target.isPort()) {
6151 auto mod = cast<FModuleLike>(target.getOp());
6152 return checks(mod.getPortType(target.getPort()),
6153 mod.getPortLocation(target.getPort()));
6155 hw::InnerSymbolOpInterface symOp =
6156 cast<hw::InnerSymbolOpInterface>(target.getOp());
6157 if (!symOp.getTargetResult())
6158 return emitOpError(
"has target that cannot be probed")
6159 .attachNote(symOp.getLoc())
6160 .append(
"target resolves here");
6162 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6163 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6164 return emitOpError(
"is not dominated by target")
6165 .attachNote(symOp.getLoc())
6166 .append(
"target here");
6167 return checks(symOp.getTargetResult().getType(), symOp.getLoc());
6174LogicalResult LayerBlockOp::verify() {
6175 auto layerName = getLayerName();
6176 auto *parentOp = (*this)->getParentOp();
6179 while (isa<WhenOp, MatchOp>(parentOp))
6180 parentOp = parentOp->getParentOp();
6184 auto nestedReferences = layerName.getNestedReferences();
6185 if (nestedReferences.empty()) {
6186 if (!isa<FModuleOp>(parentOp)) {
6187 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6188 "not have a 'firrtl.module' op as a parent";
6189 return diag.attachNote(parentOp->getLoc())
6190 <<
"illegal parent op defined here";
6193 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6194 if (!parentLayerBlock) {
6195 auto diag = emitOpError()
6196 <<
"has a nested layer symbol, but does not have a '"
6197 << getOperationName() <<
"' op as a parent'";
6198 return diag.attachNote(parentOp->getLoc())
6199 <<
"illegal parent op defined here";
6201 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6202 if (parentLayerBlockName.getRootReference() !=
6203 layerName.getRootReference() ||
6204 parentLayerBlockName.getNestedReferences() !=
6205 layerName.getNestedReferences().drop_back()) {
6206 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6207 return diag.attachNote(parentLayerBlock->getLoc())
6208 <<
"illegal parent layer block defined here";
6214 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6215 [&](Operation *op) -> WalkResult {
6217 if (isa<LayerBlockOp>(op))
6218 return WalkResult::skip();
6222 for (
auto operand : op->getOperands()) {
6224 if (
auto *definingOp = operand.getDefiningOp())
6228 auto type = operand.getType();
6231 if (isa<PropertyType>(type)) {
6232 auto diag = emitOpError() <<
"captures a property operand";
6233 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6234 diag.attachNote(op->getLoc()) <<
"operand is used here";
6235 return WalkResult::interrupt();
6240 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6242 if (isa<RefDefineOp>(connect))
6243 return WalkResult::advance();
6250 bool passive =
true;
6252 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6253 passive = type.isPassive();
6262 return WalkResult::advance();
6265 return WalkResult::advance();
6269 <<
"connects to a destination which is defined outside its "
6270 "enclosing layer block";
6271 diag.attachNote(getLoc()) <<
"enclosing layer block is defined here";
6272 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6273 return WalkResult::interrupt();
6276 return WalkResult::advance();
6279 return failure(result.wasInterrupted());
6283LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6285 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6287 return emitOpError(
"invalid symbol reference");
6298#define GET_OP_CLASSES
6299#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)