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)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void eraseInternalPaths(T op, const llvm::BitVector &portIndices)
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static LogicalResult checkConnectConditionality(FConnectLike connect)
Checks that connections to 'const' destinations are not dependent on non-'const' conditions in when b...
static void erasePorts(FModuleLike op, const llvm::BitVector &portIndices)
Erases the ports that have their corresponding bit set in portIndices.
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs)
Parse a list of module ports.
static ParseResult parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports, bool supportsInternalPaths=false)
Inserts the given ports.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
SmallSet< SymbolRefAttr, 4, CompareSymbolRefAttr > LayerSet
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static LogicalResult verifyInternalPaths(FModuleLike op, std::optional<::mlir::ArrayAttr > internalPaths)
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static LogicalResult checkConnectFlow(Operation *connect)
Check if the source and sink are of appropriate flow.
static void printParameterList(OpAsmPrinter &p, Operation *op, ArrayAttr parameters)
Print a paramter list for a module or instance.
static ParseResult parseVerifAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseElideAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding an empty 'annotations' attribute if not specified.
ParseResult parseClassLike(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static void printCircuitOpAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static LogicalResult verifyPortSymbolUses(FModuleLike module, SymbolTableCollection &symbolTable)
static void printVerifAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
Always elide "ruw" and elide "annotations" if it exists or if it is empty.
static bool isTypeAllowedForDPI(Operation *op, Type type)
static ParseResult parseElideEmptyName(OpAsmParser &p, NamedAttrList &resultAttrs)
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static InstancePath empty
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
This class represents a reference to a specific field or element of an aggregate value.
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
ExprVisitor is a visitor for FIRRTL expression nodes.
ResultType dispatchExprVisitor(Operation *op, ExtraArgs... args)
FIRRTLBaseType getMaskType()
Return this type with all ground types replaced with UInt<1>.
int32_t getBitWidthOrSentinel()
If this is an IntType, AnalogType, or sugar type for a single bit (Clock, Reset, etc) then return the...
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
FIRRTLBaseType getAllConstDroppedType()
Return this type with a 'const' modifiers dropped.
bool isPassive() const
Return true if this is a "passive" type - one that contains no "flip" types recursively within itself...
FIRRTLBaseType getConstType(bool isConst)
Return a 'const' or non-'const' version of this type.
bool isConst()
Returns true if this is a 'const' type that can only hold compile-time constant values.
Caching version of getFieldRefFromValue.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Caching version of getFieldRefFromValue.
This is the common base class between SIntType and UIntType.
int32_t getWidthOrSentinel() const
Return the width of this type, or -1 if it has none specified.
static IntType get(MLIRContext *context, bool isSigned, int32_t widthOrSentinel=-1, bool isConst=false)
Return an SIntType or UIntType with the specified signedness, width, and constness.
bool hasWidth() const
Return true if this integer type has a known width.
std::optional< int32_t > getWidth() const
Return an optional containing the width, if the width is known (or empty if width is unknown).
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
int main(int argc, char **argv)
connect(destination, source)
ClassType getInstanceTypeForClassLike(ClassLike classOp)
LogicalResult verifyTypeAgainstClassLike(ClassLike classOp, ClassType type, function_ref< InFlightDiagnostic()> emitError)
Assuming that the classOp is the source of truth, verify that the type accurately matches the signatu...
RefType getForceableResultType(bool forceable, Type type)
Return null or forceable reference result type.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
static bool unGet(Direction dir)
Convert from Direction to bool. The opposite of get;.
SmallVector< Direction > unpackAttribute(mlir::DenseBoolArrayAttr directions)
Turn a packed representation of port attributes into a vector that can be worked with.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
static StringRef toString(Direction direction)
FIRRTLType inferElementwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferBitwiseResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferAddSubResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferComparisonResult(FIRRTLType lhs, FIRRTLType rhs, std::optional< Location > loc)
FIRRTLType inferReductionResult(FIRRTLType arg, std::optional< Location > loc)
LogicalResult verifySameOperandsIntTypeKind(Operation *op)
LogicalResult verifyReferencedModule(Operation *instanceOp, SymbolTableCollection &symbolTable, mlir::FlatSymbolRefAttr moduleName)
Verify that the instance refers to a valid FIRRTL module.
BaseTy type_cast(Type type)
Flow swapFlow(Flow flow)
Get a flow's reverse.
Direction
This represents the direction of a single port.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
bool areAnonymousTypesEquivalent(FIRRTLBaseType lhs, FIRRTLBaseType rhs)
Return true if anonymous types of given arguments are equivalent by pointer comparison.
constexpr bool isValidDst(Flow flow)
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * dutAnnoClass
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
mlir::Type getPassiveType(mlir::Type anyBaseFIRRTLType)
bool isTypeLarger(FIRRTLBaseType dstType, FIRRTLBaseType srcType)
Returns true if the destination is at least as wide as a source.
bool containsConst(Type type)
Returns true if the type is or contains a 'const' type whose value is guaranteed to be unchanging at ...
bool isDuplexValue(Value val)
Returns true if the value results from an expression with duplex flow.
constexpr bool isValidSrc(Flow flow)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
BaseTy type_dyn_cast(Type type)
bool isConst(Type type)
Returns true if this is a 'const' type whose value is guaranteed to be unchanging at circuit executio...
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool isExpression(Operation *op)
Return true if the specified operation is a firrtl expression.
DeclKind getDeclarationKind(Value val)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void elideImplicitSSAName(OpAsmPrinter &printer, Operation *op, DictionaryAttr attrs, SmallVectorImpl< StringRef > &elides)
Check if the name attribute in attrs matches the SSA name of the operation's first result.
bool isAncestorOfValueOwner(Operation *op, Value value)
Return true if a Value is created "underneath" an operation.
bool inferImplicitSSAName(OpAsmParser &parser, NamedAttrList &attrs)
Ensure that attrs contains a name attribute by inferring its value from the SSA name of the operation...
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
StringAttr getFirMemoryName() const
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
This holds the name, type, direction of a module's ports.