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/Casting.h"
41#include "llvm/Support/FormatVariadic.h"
43using llvm::SmallDenseSet;
44using mlir::RegionRange;
46using namespace firrtl;
47using namespace chirrtl;
58 const llvm::BitVector &indicesToDrop) {
61 int lastIndex = indicesToDrop.find_last();
63 assert((
size_t)lastIndex < input.size() &&
"index out of range");
73 size_t lastCopied = 0;
74 SmallVector<T> result;
75 result.reserve(input.size() - indicesToDrop.count());
77 for (
unsigned indexToDrop : indicesToDrop.set_bits()) {
79 if (indexToDrop > lastCopied) {
80 result.append(input.begin() + lastCopied, input.begin() + indexToDrop);
81 lastCopied = indexToDrop;
88 if (lastCopied < input.size())
89 result.append(input.begin() + lastCopied, input.end());
95template <
typename RetTy =
FIRRTLType,
typename... Args>
97 const Twine &message, Args &&...args) {
99 (mlir::emitError(*loc, message) << ... << std::forward<Args>(args));
105 while (Operation *op = val.getDefiningOp()) {
107 TypeSwitch<Operation *, std::optional<bool>>(op)
108 .Case<SubfieldOp, SubindexOp, SubaccessOp>([&val](
auto op) {
112 .Case<RegOp, RegResetOp, WireOp>([](
auto) {
return true; })
113 .Default([](
auto) {
return false; });
120SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
121MemOp::computeDataFlow() {
124 if (getReadLatency() > 0)
126 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
128 for (
auto memPort : getResults())
129 if (auto type =
type_dyn_cast<BundleType>(memPort.getType())) {
130 auto enableFieldId = type.getFieldID((
unsigned)ReadPortSubfield::en);
131 auto addressFieldId = type.getFieldID((
unsigned)ReadPortSubfield::addr);
132 auto dataFieldId = type.getFieldID((
unsigned)ReadPortSubfield::data);
134 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
135 FieldRef(memPort,
static_cast<unsigned>(enableFieldId)));
137 FieldRef(memPort,
static_cast<unsigned>(dataFieldId)),
138 FieldRef(memPort,
static_cast<unsigned>(addressFieldId)));
145 constexpr unsigned int addr = 1 << 0;
146 constexpr unsigned int en = 1 << 1;
147 constexpr unsigned int clk = 1 << 2;
148 constexpr unsigned int data = 1 << 3;
149 constexpr unsigned int mask = 1 << 4;
150 constexpr unsigned int rdata = 1 << 5;
151 constexpr unsigned int wdata = 1 << 6;
152 constexpr unsigned int wmask = 1 << 7;
153 constexpr unsigned int wmode = 1 << 8;
154 constexpr unsigned int def = 1 << 9;
156 auto portType = type_dyn_cast<BundleType>(type);
158 return MemOp::PortKind::Debug;
161 for (
auto elem : portType.getElements()) {
162 fields |= llvm::StringSwitch<unsigned>(elem.name.getValue())
168 .Case(
"rdata",
rdata)
169 .Case(
"wdata",
wdata)
170 .Case(
"wmask",
wmask)
171 .Case(
"wmode",
wmode)
175 return MemOp::PortKind::Read;
177 return MemOp::PortKind::Write;
179 return MemOp::PortKind::ReadWrite;
180 return MemOp::PortKind::Debug;
195 llvm_unreachable(
"Unsupported Flow type.");
203 return "source flow";
207 return "duplex flow";
210 llvm_unreachable(
"Unsupported Flow type.");
215 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
216 auto *op = val.getParentBlock()->getParentOp();
217 if (
auto moduleLike = dyn_cast<FModuleLike>(op)) {
218 auto direction = moduleLike.getPortDirection(blockArg.getArgNumber());
219 if (direction == Direction::Out)
222 return accumulatedFlow;
225 Operation *op = val.getDefiningOp();
227 return TypeSwitch<Operation *, Flow>(op)
228 .Case<SubfieldOp, OpenSubfieldOp>([&](
auto op) {
229 return foldFlow(op.getInput(), op.isFieldFlipped()
233 .Case<SubindexOp, SubaccessOp, OpenSubindexOp, RefSubOp>(
234 [&](
auto op) {
return foldFlow(op.getInput(), accumulatedFlow); })
236 .Case<RegOp, RegResetOp, WireOp, MemoryPortOp>(
237 [](
auto) {
return Flow::Duplex; })
238 .Case<InstanceOp, InstanceChoiceOp>([&](
auto inst) {
239 auto resultNo = cast<OpResult>(val).getResultNumber();
240 if (inst.getPortDirection(resultNo) == Direction::Out)
241 return accumulatedFlow;
244 .Case<MemOp>([&](
auto op) {
246 if (type_isa<RefType>(val.getType()))
250 .Case<ObjectSubfieldOp>([&](ObjectSubfieldOp op) {
251 auto input = op.getInput();
252 auto *inputOp = input.getDefiningOp();
255 if (
auto objectOp = dyn_cast_or_null<ObjectOp>(inputOp)) {
256 auto classType = input.getType();
257 auto direction = classType.getElement(op.getIndex()).direction;
258 if (direction == Direction::In)
269 auto classType = input.getType();
270 auto direction = classType.getElement(op.getIndex()).direction;
271 if (direction == Direction::In)
274 op = dyn_cast_or_null<ObjectSubfieldOp>(inputOp);
276 input = op.getInput();
277 inputOp = input.getDefiningOp();
281 return accumulatedFlow;
285 .Default([&](
auto) {
return accumulatedFlow; });
291 Operation *op = val.getDefiningOp();
293 return DeclKind::Port;
295 return TypeSwitch<Operation *, DeclKind>(op)
296 .Case<InstanceOp>([](
auto) {
return DeclKind::Instance; })
297 .Case<SubfieldOp, SubindexOp, SubaccessOp, OpenSubfieldOp, OpenSubindexOp,
299 .Default([](
auto) {
return DeclKind::Other; });
303 if (
auto module = dyn_cast<FModuleLike>(op))
304 return module.getNumPorts();
305 return op->getNumResults();
319 if (
auto *op = value.getDefiningOp())
321 auto arg = dyn_cast<BlockArgument>(value);
322 auto module = dyn_cast<FModuleOp>(arg.getOwner()->getParentOp());
325 return (module.getPortSymbolAttr(arg.getArgNumber())) ||
332 OpAsmSetValueNameFn setNameFn) {
336 auto *block = ®ion.front();
339 auto argAttr = parentOp->getAttrOfType<ArrayAttr>(
"portNames");
341 if (!argAttr || argAttr.size() != block->getNumArguments())
344 for (
size_t i = 0, e = block->getNumArguments(); i != e; ++i) {
345 auto str = cast<StringAttr>(argAttr[i]).getValue();
347 setNameFn(block->getArgument(i), str);
353 firrtl::NameKindEnumAttr &result);
360struct CompareSymbolRefAttr {
362 bool operator()(SymbolRefAttr lhs, SymbolRefAttr rhs)
const {
363 auto cmp = lhs.getRootReference().compare(rhs.getRootReference());
368 auto lhsNested = lhs.getNestedReferences();
369 auto rhsNested = rhs.getNestedReferences();
370 auto lhsNestedSize = lhsNested.size();
371 auto rhsNestedSize = rhsNested.size();
372 auto e = std::min(lhsNestedSize, rhsNestedSize);
373 for (
unsigned i = 0; i < e; ++i) {
374 auto cmp = lhsNested[i].getAttr().compare(rhsNested[i].getAttr());
380 return lhsNestedSize < rhsNestedSize;
392 for (; op !=
nullptr; op = op->getParentOp()) {
393 if (
auto module = dyn_cast<FModuleLike>(op)) {
394 auto layers =
module.getLayersAttr().getAsRange<SymbolRefAttr>();
395 result.insert(layers.begin(), layers.end());
398 if (
auto layerblock = dyn_cast<LayerBlockOp>(op)) {
399 result.insert(layerblock.getLayerName());
417 if (
auto type = dyn_cast<RefType>(value.getType()))
418 if (
auto layer = type.getLayer())
419 result.insert(type.getLayer());
428 mlir::SymbolRefAttr dstLayer) {
438 if (srcLayer.getRootReference() != dstLayer.getRootReference())
441 auto srcNames = srcLayer.getNestedReferences();
442 auto dstNames = dstLayer.getNestedReferences();
443 if (dstNames.size() < srcNames.size())
446 return llvm::all_of(llvm::zip_first(srcNames, dstNames),
447 [](
auto x) {
return std::get<0>(x) == std::get<1>(x); });
454 if (dstLayers.contains(srcLayer))
459 return any_of(dstLayers, [=](SymbolRefAttr dstLayer) {
468 SmallVectorImpl<SymbolRefAttr> &missing) {
469 for (
auto srcLayer : src)
471 missing.push_back(srcLayer);
473 llvm::sort(missing, CompareSymbolRefAttr());
474 return missing.empty();
479 const Twine &errorMsg,
480 const Twine ¬eMsg = Twine(
"missing layer requirements")) {
481 SmallVector<SymbolRefAttr> missing;
484 interleaveComma(missing, op->emitOpError(errorMsg).attachNote()
493void CircuitOp::build(OpBuilder &builder, OperationState &result,
494 StringAttr name, ArrayAttr annotations) {
496 result.getOrAddProperties<Properties>().setName(name);
499 annotations = builder.getArrayAttr({});
500 result.getOrAddProperties<Properties>().setAnnotations(annotations);
503 Region *bodyRegion = result.addRegion();
505 bodyRegion->push_back(body);
509 NamedAttrList &resultAttrs) {
510 auto result = parser.parseOptionalAttrDictWithKeyword(resultAttrs);
511 if (!resultAttrs.get(
"annotations"))
512 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
518 DictionaryAttr attr) {
520 SmallVector<StringRef> elidedAttrs = {
"name"};
522 auto annotationsAttr = op->getAttrOfType<ArrayAttr>(
"annotations");
523 if (annotationsAttr.empty())
524 elidedAttrs.push_back(
"annotations");
526 p.printOptionalAttrDictWithKeyword(op->getAttrs(), elidedAttrs);
529LogicalResult CircuitOp::verifyRegions() {
534 emitOpError(
"must have a non-empty name");
538 mlir::SymbolTable symtbl(getOperation());
540 auto *mainModule = symtbl.lookup(
main);
542 return emitOpError().append(
543 "does not contain module with same name as circuit");
544 if (!isa<FModuleLike>(mainModule))
545 return mainModule->emitError(
546 "entity with name of circuit must be a module");
547 if (symtbl.getSymbolVisibility(mainModule) !=
548 mlir::SymbolTable::Visibility::Public)
549 return mainModule->emitError(
"main module must be public");
554 llvm::DenseMap<Attribute, FExtModuleOp> defnameMap;
556 auto verifyExtModule = [&](FExtModuleOp extModule) -> LogicalResult {
560 auto defname = extModule.getDefnameAttr();
566 if (
auto collidingModule = symtbl.lookup<FModuleOp>(defname.getValue()))
567 return extModule.emitOpError()
568 .append(
"attribute 'defname' with value ", defname,
569 " conflicts with the name of another module in the circuit")
570 .attachNote(collidingModule.getLoc())
571 .append(
"previous module declared here");
579 FExtModuleOp collidingExtModule;
580 if (
auto &value = defnameMap[defname]) {
581 collidingExtModule = value;
582 if (!value.getParameters().empty() && extModule.getParameters().empty())
592 SmallVector<PortInfo> ports = extModule.getPorts();
593 SmallVector<PortInfo> collidingPorts = collidingExtModule.getPorts();
595 if (ports.size() != collidingPorts.size())
596 return extModule.emitOpError()
597 .append(
"with 'defname' attribute ", defname,
" has ", ports.size(),
598 " ports which is different from a previously defined "
599 "extmodule with the same 'defname' which has ",
600 collidingPorts.size(),
" ports")
601 .attachNote(collidingExtModule.getLoc())
602 .append(
"previous extmodule definition occurred here");
608 for (
auto p :
llvm::zip(ports, collidingPorts)) {
609 StringAttr aName = std::get<0>(p).name, bName = std::get<1>(p).name;
610 Type aType = std::get<0>(p).type, bType = std::get<1>(p).type;
613 return extModule.emitOpError()
614 .append(
"with 'defname' attribute ", defname,
615 " has a port with name ", aName,
616 " which does not match the name of the port in the same "
617 "position of a previously defined extmodule with the same "
618 "'defname', expected port to have name ",
620 .attachNote(collidingExtModule.getLoc())
621 .append(
"previous extmodule definition occurred here");
623 if (!extModule.getParameters().empty() ||
624 !collidingExtModule.getParameters().empty()) {
626 if (
auto base = type_dyn_cast<FIRRTLBaseType>(aType))
627 aType = base.getWidthlessType();
628 if (
auto base = type_dyn_cast<FIRRTLBaseType>(bType))
629 bType = base.getWidthlessType();
632 return extModule.emitOpError()
633 .append(
"with 'defname' attribute ", defname,
634 " has a port with name ", aName,
635 " which has a different type ", aType,
636 " which does not match the type of the port in the same "
637 "position of a previously defined extmodule with the same "
638 "'defname', expected port to have type ",
640 .attachNote(collidingExtModule.getLoc())
641 .append(
"previous extmodule definition occurred here");
646 SmallVector<FModuleOp, 1> dutModules;
649 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
651 dutModules.push_back(moduleOp);
656 if (
auto extModule = dyn_cast<FExtModuleOp>(op)) {
657 if (verifyExtModule(extModule).failed())
663 if (dutModules.size() > 1) {
664 auto diag = dutModules[0]->emitOpError()
665 <<
"is annotated as the design-under-test (DUT), but other "
666 "modules are also annotated";
667 for (
auto moduleOp : ArrayRef(dutModules).drop_front())
668 diag.attachNote(moduleOp.
getLoc()) <<
"is also annotated as the DUT";
675Block *CircuitOp::getBodyBlock() {
return &getBody().front(); }
682 SmallVector<PortInfo> results;
683 ArrayRef<Attribute> domains =
module.getDomainInfo();
684 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
685 results.push_back({
module.getPortNameAttr(i), module.getPortType(i),
686 module.getPortDirection(i), module.getPortSymbolAttr(i),
687 module.getPortLocation(i),
688 AnnotationSet::forPort(module, i),
689 domains.empty() ? Attribute{} : domains[i]});
694SmallVector<PortInfo> FModuleOp::getPorts() { return ::getPortImpl(*
this); }
696SmallVector<PortInfo> FExtModuleOp::getPorts() { return ::getPortImpl(*
this); }
698SmallVector<PortInfo> FIntModuleOp::getPorts() { return ::getPortImpl(*
this); }
700SmallVector<PortInfo> FMemModuleOp::getPorts() { return ::getPortImpl(*
this); }
703 if (dir == Direction::In)
704 return hw::ModulePort::Direction::Input;
705 if (dir == Direction::Out)
706 return hw::ModulePort::Direction::Output;
707 assert(0 &&
"invalid direction");
712 SmallVector<hw::PortInfo> results;
713 auto aname = StringAttr::get(module.getContext(),
714 hw::HWModuleLike::getPortSymbolAttrName());
715 auto emptyDict = DictionaryAttr::get(module.getContext());
716 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i) {
717 auto sym =
module.getPortSymbolAttr(i);
719 {{
module.getPortNameAttr(i), module.getPortType(i),
720 dirFtoH(module.getPortDirection(i))},
722 sym ? DictionaryAttr::get(
724 ArrayRef<mlir::NamedAttribute>{NamedAttribute{aname, sym}})
726 module.getPortLocation(i)});
731SmallVector<::circt::hw::PortInfo> FModuleOp::getPortList() {
732 return ::getPortListImpl(*
this);
735SmallVector<::circt::hw::PortInfo> FExtModuleOp::getPortList() {
736 return ::getPortListImpl(*
this);
739SmallVector<::circt::hw::PortInfo> FIntModuleOp::getPortList() {
740 return ::getPortListImpl(*
this);
743SmallVector<::circt::hw::PortInfo> FMemModuleOp::getPortList() {
744 return ::getPortListImpl(*
this);
748 return {{
module.getPortNameAttr(idx), module.getPortType(idx),
749 dirFtoH(module.getPortDirection(idx))},
753 ArrayRef<mlir::NamedAttribute>{NamedAttribute{
754 StringAttr::get(module.getContext(),
755 hw::HWModuleLike::getPortSymbolAttrName()),
756 module.getPortSymbolAttr(idx)}}),
757 module.getPortLocation(idx)};
761 return ::getPortImpl(*
this, idx);
765 return ::getPortImpl(*
this, idx);
769 return ::getPortImpl(*
this, idx);
773 return ::getPortImpl(*
this, idx);
777BlockArgument FModuleOp::getArgument(
size_t portNumber) {
785 const SmallVectorImpl<unsigned> &numInserted) {
787 auto di = dyn_cast_or_null<ArrayAttr>(domainInfoAttr);
789 return domainInfoAttr;
791 SmallVector<Attribute> domainInfo;
792 for (
auto attr : di) {
793 auto oldIdx = cast<IntegerAttr>(attr).getUInt();
794 auto newIdx = oldIdx + numInserted[oldIdx];
795 if (oldIdx == newIdx)
796 domainInfo.push_back(attr);
798 domainInfo.push_back(IntegerAttr::get(
799 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
801 return ArrayAttr::get(context, domainInfo);
808 ArrayRef<std::pair<unsigned, PortInfo>> ports,
809 bool supportsInternalPaths =
false) {
812 unsigned oldNumArgs = op.getNumPorts();
813 unsigned newNumArgs = oldNumArgs + ports.size();
816 auto existingDirections = op.getPortDirectionsAttr();
817 ArrayRef<Attribute> existingNames = op.getPortNames();
818 ArrayRef<Attribute> existingTypes = op.getPortTypes();
819 ArrayRef<Attribute> existingLocs = op.getPortLocations();
820 assert(existingDirections.size() == oldNumArgs);
821 assert(existingNames.size() == oldNumArgs);
822 assert(existingTypes.size() == oldNumArgs);
823 assert(existingLocs.size() == oldNumArgs);
824 SmallVector<Attribute> internalPaths;
825 auto emptyInternalPath = InternalPathAttr::get(op.getContext());
826 if (supportsInternalPaths) {
827 if (
auto internalPathsAttr = op->getAttrOfType<ArrayAttr>(
"internalPaths"))
828 llvm::append_range(internalPaths, internalPathsAttr);
830 internalPaths.resize(oldNumArgs, emptyInternalPath);
831 assert(internalPaths.size() == oldNumArgs);
834 SmallVector<bool> newDirections;
835 SmallVector<Attribute> newNames, newTypes, newDomains, newAnnos, newSyms,
836 newLocs, newInternalPaths;
837 SmallVector<unsigned> numInserted;
838 newDirections.reserve(newNumArgs);
839 newNames.reserve(newNumArgs);
840 newTypes.reserve(newNumArgs);
841 newDomains.reserve(newNumArgs);
842 newAnnos.reserve(newNumArgs);
843 newSyms.reserve(newNumArgs);
844 newLocs.reserve(newNumArgs);
845 newInternalPaths.reserve(newNumArgs);
846 numInserted.resize(op.getNumPorts());
848 auto emptyArray = ArrayAttr::get(op.getContext(), {});
851 auto migrateOldPorts = [&](
unsigned untilOldIdx) {
852 while (oldIdx < oldNumArgs && oldIdx < untilOldIdx) {
853 newDirections.push_back(existingDirections[oldIdx]);
854 newNames.push_back(existingNames[oldIdx]);
855 newTypes.push_back(existingTypes[oldIdx]);
857 op.getContext(), op.getDomainInfoAttrForPort(oldIdx), numInserted));
858 newAnnos.push_back(op.getAnnotationsAttrForPort(oldIdx));
859 newSyms.push_back(op.getPortSymbolAttr(oldIdx));
860 newLocs.push_back(existingLocs[oldIdx]);
861 if (supportsInternalPaths)
862 newInternalPaths.push_back(internalPaths[oldIdx]);
866 numInserted[oldIdx] = numInserted[oldIdx - 1];
870 for (
auto pair : llvm::enumerate(ports)) {
871 auto idx = pair.value().first;
872 auto &port = pair.value().second;
873 migrateOldPorts(idx);
875 newNames.push_back(port.name);
876 newTypes.push_back(TypeAttr::get(port.type));
879 port.domains ? port.domains : ArrayAttr::get(op.getContext(), {}),
881 auto annos = port.annotations.getArrayAttr();
882 newAnnos.push_back(annos ? annos : emptyArray);
883 newSyms.push_back(port.sym);
884 newLocs.push_back(port.loc);
885 if (supportsInternalPaths)
886 newInternalPaths.push_back(emptyInternalPath);
887 if (idx < oldNumArgs)
888 numInserted[idx] += 1;
890 migrateOldPorts(oldNumArgs);
894 if (llvm::all_of(newAnnos, [](Attribute attr) {
895 return cast<ArrayAttr>(attr).empty();
901 if (llvm::all_of(newDomains, [](Attribute attr) {
904 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
905 return arrayAttr.empty();
911 op->setAttr(
"portDirections",
913 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newNames));
914 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newTypes));
915 op->setAttr(
"domainInfo", ArrayAttr::get(op.getContext(), newDomains));
916 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newAnnos));
917 FModuleLike::fixupPortSymsArray(newSyms, op.getContext());
918 op.setPortSymbols(newSyms);
919 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newLocs));
920 if (supportsInternalPaths) {
922 auto empty = llvm::all_of(newInternalPaths, [](Attribute attr) {
923 return !cast<InternalPathAttr>(attr).getPath();
926 op->removeAttr(
"internalPaths");
928 op->setAttr(
"internalPaths",
929 ArrayAttr::get(op.getContext(), newInternalPaths));
941 ArrayAttr domainInfoAttr,
942 const llvm::BitVector &portIndices,
943 bool supportsEmptyAttr) {
944 if (supportsEmptyAttr && domainInfoAttr.empty())
945 return domainInfoAttr;
949 SmallVector<unsigned> numDeleted;
950 numDeleted.resize(portIndices.size());
951 size_t deletionIndex = portIndices.find_first();
952 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
953 if (i == deletionIndex) {
957 numDeleted[i] = numDeleted[i - 1] + 1;
958 deletionIndex = portIndices.find_next(i);
964 numDeleted[i] = numDeleted[i - 1];
969 auto getEmpty = [&]() {
971 eEmpty = ArrayAttr::get(context, {});
976 SmallVector<Attribute> newPortDomains;
977 newPortDomains.reserve(portIndices.size() - portIndices.count());
978 for (
size_t i = 0, e = portIndices.size(); i != e; ++i) {
980 if (portIndices.test(i))
983 if (domainInfoAttr.empty()) {
984 newPortDomains.push_back(getEmpty());
987 auto attr = domainInfoAttr[i];
989 auto domains = dyn_cast<ArrayAttr>(attr);
990 if (!domains || domains.empty()) {
991 newPortDomains.push_back(attr);
995 for (
auto domain : domains) {
997 auto oldIdx = cast<IntegerAttr>(domain).getUInt();
998 if (portIndices.test(oldIdx))
1001 auto newIdx = oldIdx - numDeleted[oldIdx];
1002 if (oldIdx == newIdx) {
1003 newPortDomains.push_back(attr);
1007 newPortDomains.push_back(IntegerAttr::get(
1008 IntegerType::get(context, 32, IntegerType::Unsigned), newIdx));
1012 return ArrayAttr::get(context, newPortDomains);
1016static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
1017 if (portIndices.none())
1021 ArrayRef<bool> portDirections = op.getPortDirectionsAttr().asArrayRef();
1022 ArrayRef<Attribute> portNames = op.getPortNames();
1023 ArrayRef<Attribute> portTypes = op.getPortTypes();
1024 ArrayRef<Attribute> portAnnos = op.getPortAnnotations();
1025 ArrayRef<Attribute> portSyms = op.getPortSymbols();
1026 ArrayRef<Attribute> portLocs = op.getPortLocations();
1027 ArrayRef<Attribute> portDomains = op.getDomainInfo();
1028 auto numPorts = op.getNumPorts();
1030 assert(portDirections.size() == numPorts);
1031 assert(portNames.size() == numPorts);
1032 assert(portAnnos.size() == numPorts || portAnnos.empty());
1033 assert(portTypes.size() == numPorts);
1034 assert(portSyms.size() == numPorts || portSyms.empty());
1035 assert(portLocs.size() == numPorts);
1036 assert(portDomains.size() == numPorts || portDomains.empty());
1038 SmallVector<bool> newPortDirections =
1039 removeElementsAtIndices<bool>(portDirections, portIndices);
1040 SmallVector<Attribute> newPortNames, newPortTypes, newPortAnnos, newPortSyms,
1048 op->setAttr(
"portDirections",
1050 op->setAttr(
"portNames", ArrayAttr::get(op.getContext(), newPortNames));
1051 op->setAttr(
"portAnnotations", ArrayAttr::get(op.getContext(), newPortAnnos));
1052 op->setAttr(
"portTypes", ArrayAttr::get(op.getContext(), newPortTypes));
1053 FModuleLike::fixupPortSymsArray(newPortSyms, op.getContext());
1054 op->setAttr(
"portSymbols", ArrayAttr::get(op.getContext(), newPortSyms));
1055 op->setAttr(
"portLocations", ArrayAttr::get(op.getContext(), newPortLocs));
1056 op->setAttr(
"domainInfo",
1058 portIndices,
true));
1016static void erasePorts(FModuleLike op,
const llvm::BitVector &portIndices) {
…}
1061template <
typename T>
1064 auto internalPaths = op.getInternalPaths();
1072 auto empty = llvm::all_of(newPaths, [](Attribute attr) {
1073 return !cast<InternalPathAttr>(attr).getPath();
1076 op.removeInternalPathsAttr();
1078 op.setInternalPathsAttr(ArrayAttr::get(op.getContext(), newPaths));
1081void FExtModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1082 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1086void FIntModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1087 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1091void FMemModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1092 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1095void FModuleOp::erasePorts(
const llvm::BitVector &portIndices) {
1096 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
1103void FModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1104 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1108 for (
size_t i = 0, e = ports.size(); i < e; ++i) {
1111 auto &[index, port] = ports[i];
1112 body->insertArgument(index + i, port.type, port.loc);
1116void FExtModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1121void FIntModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1129void FMemModuleOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
1130 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
1133template <
typename OpTy>
1135 StringAttr name, ArrayRef<PortInfo> ports) {
1137 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1138 properties.setSymName(name);
1141 SmallVector<Direction, 4> portDirections;
1142 SmallVector<Attribute, 4> portNames;
1143 SmallVector<Attribute, 4> portTypes;
1144 SmallVector<Attribute, 4> portSyms;
1145 SmallVector<Attribute, 4> portLocs;
1146 SmallVector<Attribute, 4> portDomains;
1147 for (
const auto &port : ports) {
1148 portDirections.push_back(port.direction);
1149 portNames.push_back(port.name);
1150 portTypes.push_back(TypeAttr::get(port.type));
1151 portSyms.push_back(port.sym);
1152 portLocs.push_back(port.loc);
1153 portDomains.push_back(port.domains);
1155 if (llvm::all_of(portDomains, [](Attribute attr) {
1158 if (
auto arrayAttr = dyn_cast<ArrayAttr>(attr))
1159 return arrayAttr.empty();
1162 portDomains.clear();
1164 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1167 properties.setPortDirections(
1169 properties.setPortNames(builder.getArrayAttr(portNames));
1170 properties.setPortTypes(builder.getArrayAttr(portTypes));
1171 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1172 properties.setPortLocations(builder.getArrayAttr(portLocs));
1173 properties.setDomainInfo(builder.getArrayAttr(portDomains));
1178template <
typename OpTy>
1180 StringAttr name, ArrayRef<PortInfo> ports,
1181 ArrayAttr annotations, ArrayAttr layers) {
1182 buildModuleLike<OpTy>(builder, result, name, ports);
1183 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
1186 annotations = builder.getArrayAttr({});
1187 properties.setAnnotations(annotations);
1191 SmallVector<Attribute, 4> portAnnotations;
1192 for (
const auto &port : ports)
1193 portAnnotations.push_back(port.annotations.getArrayAttr());
1194 if (llvm::all_of(portAnnotations, [](Attribute attr) {
1195 return cast<ArrayAttr>(attr).empty();
1197 portAnnotations.clear();
1198 properties.setPortAnnotations(builder.getArrayAttr(portAnnotations));
1202 layers = builder.getArrayAttr({});
1203 properties.setLayers(layers);
1206template <
typename OpTy>
1207static void buildClass(OpBuilder &builder, OperationState &result,
1208 StringAttr name, ArrayRef<PortInfo> ports) {
1209 return buildModuleLike<OpTy>(builder, result, name, ports);
1212void FModuleOp::build(OpBuilder &builder, OperationState &result,
1213 StringAttr name, ConventionAttr convention,
1214 ArrayRef<PortInfo> ports, ArrayAttr annotations,
1216 buildModule<FModuleOp>(builder, result, name, ports, annotations, layers);
1217 auto &properties = result.getOrAddProperties<Properties>();
1218 properties.setConvention(convention);
1221 auto *bodyRegion = result.regions[0].get();
1223 bodyRegion->push_back(body);
1226 for (
auto &elt : ports)
1227 body->addArgument(elt.type, elt.loc);
1230void FExtModuleOp::build(OpBuilder &builder, OperationState &result,
1231 StringAttr name, ConventionAttr convention,
1232 ArrayRef<PortInfo> ports, ArrayAttr knownLayers,
1233 StringRef defnameAttr, ArrayAttr annotations,
1234 ArrayAttr parameters, ArrayAttr internalPaths,
1236 buildModule<FExtModuleOp>(builder, result, name, ports, annotations, layers);
1237 auto &properties = result.getOrAddProperties<Properties>();
1238 properties.setConvention(convention);
1240 knownLayers = builder.getArrayAttr({});
1241 properties.setKnownLayers(knownLayers);
1242 if (!defnameAttr.empty())
1243 properties.setDefname(builder.getStringAttr(defnameAttr));
1245 parameters = builder.getArrayAttr({});
1246 properties.setParameters(parameters);
1247 if (internalPaths && !internalPaths.empty())
1248 properties.setInternalPaths(internalPaths);
1251void FIntModuleOp::build(OpBuilder &builder, OperationState &result,
1252 StringAttr name, ArrayRef<PortInfo> ports,
1253 StringRef intrinsicNameStr, ArrayAttr annotations,
1254 ArrayAttr parameters, ArrayAttr internalPaths,
1256 buildModule<FIntModuleOp>(builder, result, name, ports, annotations, layers);
1257 auto &properties = result.getOrAddProperties<Properties>();
1258 properties.setIntrinsic(builder.getStringAttr(intrinsicNameStr));
1260 parameters = builder.getArrayAttr({});
1261 properties.setParameters(parameters);
1262 if (internalPaths && !internalPaths.empty())
1263 properties.setInternalPaths(internalPaths);
1266void FMemModuleOp::build(OpBuilder &builder, OperationState &result,
1267 StringAttr name, ArrayRef<PortInfo> ports,
1268 uint32_t numReadPorts, uint32_t numWritePorts,
1269 uint32_t numReadWritePorts, uint32_t dataWidth,
1270 uint32_t maskBits, uint32_t readLatency,
1271 uint32_t writeLatency, uint64_t depth, RUWBehavior ruw,
1272 ArrayAttr annotations, ArrayAttr layers) {
1273 auto *context = builder.getContext();
1274 buildModule<FMemModuleOp>(builder, result, name, ports, annotations, layers);
1275 auto ui32Type = IntegerType::get(context, 32, IntegerType::Unsigned);
1276 auto ui64Type = IntegerType::get(context, 64, IntegerType::Unsigned);
1277 auto &properties = result.getOrAddProperties<Properties>();
1278 properties.setNumReadPorts(IntegerAttr::get(ui32Type, numReadPorts));
1279 properties.setNumWritePorts(IntegerAttr::get(ui32Type, numWritePorts));
1280 properties.setNumReadWritePorts(
1281 IntegerAttr::get(ui32Type, numReadWritePorts));
1282 properties.setDataWidth(IntegerAttr::get(ui32Type, dataWidth));
1283 properties.setMaskBits(IntegerAttr::get(ui32Type, maskBits));
1284 properties.setReadLatency(IntegerAttr::get(ui32Type, readLatency));
1285 properties.setWriteLatency(IntegerAttr::get(ui32Type, writeLatency));
1286 properties.setDepth(IntegerAttr::get(ui64Type, depth));
1287 properties.setExtraPorts(ArrayAttr::get(context, {}));
1288 properties.setRuw(RUWBehaviorAttr::get(context, ruw));
1305 ArrayRef<Attribute> portNames, ArrayRef<Attribute> portTypes,
1306 ArrayRef<Attribute> portAnnotations,
1307 ArrayRef<Attribute> portSyms, ArrayRef<Attribute> portLocs,
1308 ArrayRef<Attribute> domainInfo) {
1311 bool printedNamesDontMatch =
false;
1313 mlir::OpPrintingFlags flags;
1317 SmallString<32> resultNameStr;
1318 DenseMap<unsigned, std::string> domainPortNames;
1320 for (
unsigned i = 0, e = portTypes.size(); i < e; ++i) {
1329 auto portType = cast<TypeAttr>(portTypes[i]).getValue();
1332 resultNameStr.clear();
1333 llvm::raw_svector_ostream tmpStream(resultNameStr);
1334 p.printOperand(block->getArgument(i), tmpStream);
1337 auto portName = cast<StringAttr>(portNames[i]).getValue();
1338 if (tmpStream.str().drop_front() != portName)
1339 printedNamesDontMatch =
true;
1340 p << tmpStream.str();
1341 if (isa<DomainType>(portType))
1342 domainPortNames[i] = tmpStream.str();
1344 auto name = cast<StringAttr>(portNames[i]).getValue();
1345 p.printKeywordOrString(name);
1346 if (isa<DomainType>(portType))
1347 domainPortNames[i] = name.str();
1352 p.printType(portType);
1355 if (!portSyms.empty()) {
1356 if (!cast<hw::InnerSymAttr>(portSyms[i]).
empty()) {
1358 cast<hw::InnerSymAttr>(portSyms[i]).print(p);
1363 if (!domainInfo.empty()) {
1364 if (
auto domainKind = dyn_cast<FlatSymbolRefAttr>(domainInfo[i])) {
1365 p <<
" of " << domainKind;
1367 auto domains = cast<ArrayAttr>(domainInfo[i]);
1368 if (!domains.empty()) {
1370 llvm::interleaveComma(domains, p, [&](Attribute attr) {
1371 p << domainPortNames[cast<IntegerAttr>(attr).getUInt()];
1380 if (!portAnnotations.empty() &&
1381 !cast<ArrayAttr>(portAnnotations[i]).empty()) {
1383 p.printAttribute(portAnnotations[i]);
1390 if (flags.shouldPrintDebugInfo() && !portLocs.empty())
1391 p.printOptionalLocationSpecifier(cast<LocationAttr>(portLocs[i]));
1395 return printedNamesDontMatch;
1401 OpAsmParser &parser,
bool hasSSAIdentifiers,
bool supportsSymbols,
1402 bool supportsDomains, SmallVectorImpl<OpAsmParser::Argument> &entryArgs,
1403 SmallVectorImpl<Direction> &portDirections,
1404 SmallVectorImpl<Attribute> &portNames,
1405 SmallVectorImpl<Attribute> &portTypes,
1406 SmallVectorImpl<Attribute> &portAnnotations,
1407 SmallVectorImpl<Attribute> &portSyms, SmallVectorImpl<Attribute> &portLocs,
1408 SmallVectorImpl<Attribute> &domains) {
1409 auto *context = parser.getContext();
1412 DenseMap<Attribute, size_t> domainIndex;
1414 auto parseArgument = [&]() -> ParseResult {
1416 if (succeeded(parser.parseOptionalKeyword(
"out")))
1417 portDirections.push_back(Direction::Out);
1418 else if (succeeded(parser.parseKeyword(
"in",
" or 'out'")))
1419 portDirections.push_back(Direction::In);
1427 if (hasSSAIdentifiers) {
1428 OpAsmParser::Argument arg;
1429 if (parser.parseArgument(arg))
1431 entryArgs.push_back(arg);
1435 assert(arg.ssaName.name.size() > 1 && arg.ssaName.name[0] ==
'%' &&
1436 "Unknown MLIR name");
1437 if (
isdigit(arg.ssaName.name[1]))
1438 portNames.push_back(StringAttr::get(context,
""));
1440 portNames.push_back(
1441 StringAttr::get(context, arg.ssaName.name.drop_front()));
1444 irLoc = arg.ssaName.location;
1448 irLoc = parser.getCurrentLocation();
1449 std::string portName;
1450 if (parser.parseKeywordOrString(&portName))
1452 portNames.push_back(StringAttr::get(context, portName));
1457 if (parser.parseColonType(portType))
1459 portTypes.push_back(TypeAttr::get(portType));
1460 if (isa<DomainType>(portType))
1461 domainIndex[portNames.back()] = portNames.size() - 1;
1463 if (hasSSAIdentifiers)
1464 entryArgs.back().type = portType;
1467 if (supportsSymbols) {
1468 hw::InnerSymAttr innerSymAttr;
1469 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
1470 NamedAttrList dummyAttrs;
1471 if (parser.parseCustomAttributeWithFallback(
1472 innerSymAttr, ::mlir::Type{},
1474 return ::mlir::failure();
1477 portSyms.push_back(innerSymAttr);
1481 Attribute domainsAttr;
1482 SmallVector<Attribute> portDomains;
1483 if (supportsDomains) {
1484 if (isa<DomainType>(portType)) {
1485 if (parser.parseKeyword(
"of"))
1487 StringAttr domainKind;
1488 if (parser.parseSymbolName(domainKind))
1490 domainsAttr = FlatSymbolRefAttr::get(context, domainKind);
1491 }
else if (succeeded(parser.parseOptionalKeyword(
"domains"))) {
1492 auto result = parser.parseCommaSeparatedList(
1493 OpAsmParser::Delimiter::Square, [&]() -> ParseResult {
1495 if (hasSSAIdentifiers) {
1496 OpAsmParser::Argument arg;
1497 if (parser.parseArgument(arg))
1500 StringAttr::get(context, arg.ssaName.name.drop_front());
1502 std::string portName;
1503 if (parser.parseKeywordOrString(&portName))
1505 argName = StringAttr::get(context, portName);
1508 auto index = domainIndex.find(argName);
1509 if (index == domainIndex.end()) {
1510 parser.emitError(irLoc)
1511 <<
"domain name '" << argName <<
"' not found";
1514 portDomains.push_back(IntegerAttr::get(
1515 IntegerType::get(context, 32, IntegerType::Unsigned),
1521 domainsAttr = parser.getBuilder().getArrayAttr(portDomains);
1525 domainsAttr = parser.getBuilder().getArrayAttr({});
1526 domains.push_back(domainsAttr);
1530 auto parseResult = parser.parseOptionalAttribute(annos);
1531 if (!parseResult.has_value())
1532 annos = parser.getBuilder().getArrayAttr({});
1533 else if (failed(*parseResult))
1535 portAnnotations.push_back(annos);
1538 std::optional<Location> maybeLoc;
1539 if (failed(parser.parseOptionalLocationSpecifier(maybeLoc)))
1541 Location loc = maybeLoc ? *maybeLoc : parser.getEncodedSourceLoc(irLoc);
1542 portLocs.push_back(loc);
1543 if (hasSSAIdentifiers)
1544 entryArgs.back().sourceLoc = loc;
1550 return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
1556 ArrayAttr parameters) {
1557 if (!parameters || parameters.empty())
1561 llvm::interleaveComma(parameters, p, [&](Attribute param) {
1562 auto paramAttr = cast<ParamDeclAttr>(param);
1563 p << paramAttr.getName().getValue() <<
": " << paramAttr.getType();
1564 if (
auto value = paramAttr.getValue()) {
1566 p.printAttributeWithoutType(value);
1576 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
1577 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
1578 p << visibility.getValue() <<
' ';
1581 p.printSymbolName(op.getModuleName());
1588 Block *body =
nullptr;
1589 if (!op->getRegion(0).empty())
1590 body = &op->getRegion(0).front();
1593 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
1594 op.getPortAnnotations(), op.getPortSymbols(), op.getPortLocations(),
1595 op.getDomainInfo());
1597 SmallVector<StringRef, 13> omittedAttrs = {
1598 "sym_name",
"portDirections",
"portTypes",
1599 "portAnnotations",
"portSymbols",
"portLocations",
1600 "parameters", visibilityAttrName,
"domainInfo"};
1602 if (op.getConvention() == Convention::Internal)
1603 omittedAttrs.push_back(
"convention");
1607 if (!needPortNamesAttr)
1608 omittedAttrs.push_back(
"portNames");
1611 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
1612 omittedAttrs.push_back(
"annotations");
1615 if (
auto knownLayers = op->getAttrOfType<ArrayAttr>(
"knownLayers"))
1616 if (knownLayers.empty())
1617 omittedAttrs.push_back(
"knownLayers");
1620 if (
auto layers = op->getAttrOfType<ArrayAttr>(
"layers"))
1622 omittedAttrs.push_back(
"layers");
1624 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
1633void FModuleOp::print(OpAsmPrinter &p) {
1639 Region &fbody = getBody();
1640 if (!fbody.empty()) {
1642 p.printRegion(fbody,
false,
1654 SmallVectorImpl<Attribute> ¶meters) {
1656 return parser.parseCommaSeparatedList(
1657 OpAsmParser::Delimiter::OptionalLessGreater, [&]() {
1662 if (parser.parseKeywordOrString(&name) || parser.parseColonType(type))
1666 if (succeeded(parser.parseOptionalEqual())) {
1667 if (parser.parseAttribute(value, type))
1671 auto &builder = parser.getBuilder();
1672 parameters.push_back(ParamDeclAttr::get(
1673 builder.getContext(), builder.getStringAttr(name), type, value));
1680 ArrayAttr ¶meters) {
1681 SmallVector<Attribute> parseParameters;
1685 parameters = ArrayAttr::get(parser.getContext(), parseParameters);
1690template <
typename Properties,
typename =
void>
1693template <
typename Properties>
1695 Properties, std::void_t<decltype(std::declval<Properties>().parameters)>>
1696 : std::true_type {};
1698template <
typename OpTy>
1700 OperationState &result,
1701 bool hasSSAIdentifiers) {
1702 auto *context = result.getContext();
1703 auto &builder = parser.getBuilder();
1704 using Properties =
typename OpTy::Properties;
1705 auto &properties = result.getOrAddProperties<Properties>();
1709 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
1712 StringAttr nameAttr;
1713 if (parser.parseSymbolName(nameAttr))
1715 properties.setSymName(nameAttr);
1719 SmallVector<Attribute, 4> parameters;
1722 properties.setParameters(builder.getArrayAttr(parameters));
1726 SmallVector<OpAsmParser::Argument> entryArgs;
1727 SmallVector<Direction, 4> portDirections;
1728 SmallVector<Attribute, 4> portNames;
1729 SmallVector<Attribute, 4> portTypes;
1730 SmallVector<Attribute, 4> portAnnotations;
1731 SmallVector<Attribute, 4> portSyms;
1732 SmallVector<Attribute, 4> portLocs;
1733 SmallVector<Attribute, 4> domains;
1735 true, entryArgs, portDirections,
1736 portNames, portTypes, portAnnotations, portSyms,
1741 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
1744 assert(portNames.size() == portTypes.size());
1750 properties.setPortDirections(
1754 properties.setPortNames(builder.getArrayAttr(portNames));
1757 properties.setPortTypes(ArrayAttr::get(context, portTypes));
1761 if (llvm::any_of(portAnnotations, [&](Attribute anno) {
1762 return !cast<ArrayAttr>(anno).empty();
1764 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
1766 properties.setPortAnnotations(builder.getArrayAttr({}));
1769 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
1770 properties.setPortSymbols(builder.getArrayAttr(portSyms));
1773 properties.setPortLocations(ArrayAttr::get(context, portLocs));
1776 properties.setAnnotations(builder.getArrayAttr({}));
1779 properties.setDomainInfo(ArrayAttr::get(context, domains));
1782 auto *body = result.addRegion();
1784 if (hasSSAIdentifiers) {
1785 if (parser.parseRegion(*body, entryArgs))
1788 body->push_back(
new Block());
1793ParseResult FModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1794 if (parseFModuleLikeOp<FModuleOp>(parser, result,
1797 auto &properties = result.getOrAddProperties<Properties>();
1798 properties.setConvention(
1799 ConventionAttr::get(result.getContext(), Convention::Internal));
1800 properties.setLayers(ArrayAttr::get(parser.getContext(), {}));
1804ParseResult FExtModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1805 if (parseFModuleLikeOp<FExtModuleOp>(parser, result,
1808 auto &properties = result.getOrAddProperties<Properties>();
1809 properties.setConvention(
1810 ConventionAttr::get(result.getContext(), Convention::Internal));
1811 properties.setKnownLayers(ArrayAttr::get(result.getContext(), {}));
1815ParseResult FIntModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1816 return parseFModuleLikeOp<FIntModuleOp>(parser, result,
1820ParseResult FMemModuleOp::parse(OpAsmParser &parser, OperationState &result) {
1821 return parseFModuleLikeOp<FMemModuleOp>(parser, result,
1825LogicalResult FModuleOp::verify() {
1828 auto portTypes = getPortTypes();
1829 auto portLocs = getPortLocations();
1830 auto numPorts = portTypes.size();
1833 if (body->getNumArguments() != numPorts)
1834 return emitOpError(
"entry block must have ")
1835 << numPorts <<
" arguments to match module signature";
1838 for (
auto [arg, type, loc] : zip(body->getArguments(), portTypes, portLocs)) {
1839 if (arg.getType() != cast<TypeAttr>(type).getValue())
1840 return emitOpError(
"block argument types should match signature types");
1841 if (arg.getLoc() != cast<LocationAttr>(loc))
1843 "block argument locations should match signature locations");
1851 std::optional<::mlir::ArrayAttr> internalPaths) {
1856 if (internalPaths->size() != op.getNumPorts())
1857 return op.emitError(
"module has inconsistent internal path array with ")
1858 << internalPaths->size() <<
" entries for " << op.getNumPorts()
1862 for (
auto [idx, path, typeattr] : llvm::enumerate(
1863 internalPaths->getAsRange<InternalPathAttr>(), op.getPortTypes())) {
1864 if (path.getPath() &&
1865 !type_isa<RefType>(cast<TypeAttr>(typeattr).getValue())) {
1867 op.emitError(
"module has internal path for non-ref-type port ")
1868 << op.getPortNameAttr(idx);
1869 return diag.attachNote(op.getPortLocation(idx)) <<
"this port";
1876LogicalResult FExtModuleOp::verify() {
1880 auto params = getParameters();
1882 auto checkParmValue = [&](Attribute elt) ->
bool {
1883 auto param = cast<ParamDeclAttr>(elt);
1884 auto value = param.getValue();
1885 if (isa<IntegerAttr, StringAttr, FloatAttr, hw::ParamVerbatimAttr>(value))
1887 emitError() <<
"has unknown extmodule parameter value '"
1888 << param.getName().getValue() <<
"' = " << value;
1892 if (!llvm::all_of(params, checkParmValue))
1897 known.insert_range(getKnownLayersAttr().getAsRange<SymbolRefAttr>());
1900 referenced.insert_range(getLayersAttr().getAsRange<SymbolRefAttr>());
1901 for (
auto attr : getPortTypes()) {
1902 auto type = cast<TypeAttr>(attr).getValue();
1903 if (
auto refType = type_dyn_cast<RefType>(type))
1904 if (
auto layer = refType.getLayer())
1905 referenced.insert(layer);
1909 "references unknown layers",
"unknown layers");
1912LogicalResult FIntModuleOp::verify() {
1916 auto params = getParameters();
1920 auto checkParmValue = [&](Attribute elt) ->
bool {
1921 auto param = cast<ParamDeclAttr>(elt);
1922 auto value = param.getValue();
1923 if (isa<IntegerAttr, StringAttr, FloatAttr>(value))
1925 emitError() <<
"has unknown intmodule parameter value '"
1926 << param.getName().getValue() <<
"' = " << value;
1930 if (!llvm::all_of(params, checkParmValue))
1937 CircuitOp circuitOp,
1938 SymbolTableCollection &symbolTable,
1940 auto layer = refType.getLayer();
1943 auto *layerOp = symbolTable.lookupSymbolIn(circuitOp, layer);
1945 return emitError(loc) << start <<
" associated with layer '" << layer
1946 <<
"', but this layer was not defined";
1947 if (!isa<LayerOp>(layerOp)) {
1948 auto diag = emitError(loc)
1949 << start <<
" associated with layer '" << layer
1950 <<
"', but symbol '" << layer <<
"' does not refer to a '"
1951 << LayerOp::getOperationName() <<
"' op";
1952 return diag.attachNote(layerOp->getLoc()) <<
"symbol refers to this op";
1958 SymbolTableCollection &symbolTable) {
1960 auto circuitOp =
module->getParentOfType<CircuitOp>();
1961 for (
size_t i = 0, e = module.getNumPorts(); i < e; ++i) {
1962 auto type =
module.getPortType(i);
1964 if (
auto refType = type_dyn_cast<RefType>(type)) {
1966 refType, module.getPortLocation(i), circuitOp, symbolTable,
1967 Twine(
"probe port '") + module.getPortName(i) +
"' is")))
1972 if (
auto classType = dyn_cast<ClassType>(type)) {
1973 auto className = classType.getNameAttr();
1974 auto classOp = dyn_cast_or_null<ClassLike>(
1975 symbolTable.lookupSymbolIn(circuitOp, className));
1977 return module.emitOpError() << "references unknown class " << className;
1980 if (failed(classOp.verifyType(classType,
1981 [&]() { return module.emitOpError(); })))
1986 if (isa<DomainType>(type)) {
1987 auto domainInfo =
module.getDomainInfoAttrForPort(i);
1988 if (
auto kind = dyn_cast<FlatSymbolRefAttr>(domainInfo))
1989 if (!dyn_cast_or_null<DomainOp>(
1990 symbolTable.lookupSymbolIn(circuitOp, kind)))
1991 return mlir::emitError(module.getPortLocation(i))
1992 <<
"domain port '" <<
module.getPortName(i)
1993 << "' has undefined domain kind '" << kind.getValue() << "'";
2000LogicalResult FModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2004 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
2005 for (
auto layer : getLayers()) {
2006 if (!symbolTable.lookupSymbolIn(circuitOp, cast<SymbolRefAttr>(layer)))
2007 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
2014FExtModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2018 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
2019 for (
auto layer : getKnownLayersAttr().getAsRange<SymbolRefAttr>()) {
2020 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
2021 return emitOpError() <<
"knows undefined layer '" << layer <<
"'";
2023 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>()) {
2024 if (!symbolTable.lookupSymbolIn(circuitOp, layer))
2025 return emitOpError() <<
"enables undefined layer '" << layer <<
"'";
2032FIntModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2037FMemModuleOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2041void FModuleOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2046void FExtModuleOp::getAsmBlockArgumentNames(
2051void FIntModuleOp::getAsmBlockArgumentNames(
2056void FMemModuleOp::getAsmBlockArgumentNames(
2061ArrayAttr FMemModuleOp::getParameters() {
return {}; }
2063ArrayAttr FModuleOp::getParameters() {
return {}; }
2065Convention FIntModuleOp::getConvention() {
return Convention::Internal; }
2067ConventionAttr FIntModuleOp::getConventionAttr() {
2068 return ConventionAttr::get(getContext(), getConvention());
2071Convention FMemModuleOp::getConvention() {
return Convention::Internal; }
2073ConventionAttr FMemModuleOp::getConventionAttr() {
2074 return ConventionAttr::get(getContext(), getConvention());
2082 ClassLike classOp, ClassType type,
2083 function_ref<InFlightDiagnostic()> emitError) {
2085 auto name = type.getNameAttr().getAttr();
2086 auto expectedName = classOp.getModuleNameAttr();
2087 if (name != expectedName)
2088 return emitError() <<
"type has wrong name, got " << name <<
", expected "
2091 auto elements = type.getElements();
2093 auto expectedNumElements = classOp.getNumPorts();
2095 return emitError() <<
"has wrong number of ports, got " <<
numElements
2096 <<
", expected " << expectedNumElements;
2098 auto portNames = classOp.getPortNames();
2099 auto portDirections = classOp.getPortDirections();
2100 auto portTypes = classOp.getPortTypes();
2103 auto element = elements[i];
2105 auto name = element.name;
2106 auto expectedName = portNames[i];
2107 if (name != expectedName)
2108 return emitError() <<
"port #" << i <<
" has wrong name, got " << name
2109 <<
", expected " << expectedName;
2111 auto direction = element.direction;
2112 auto expectedDirection =
Direction(portDirections[i]);
2113 if (direction != expectedDirection)
2114 return emitError() <<
"port " << name <<
" has wrong direction, got "
2118 auto type = element.type;
2119 auto expectedType = cast<TypeAttr>(portTypes[i]).getValue();
2120 if (type != expectedType)
2121 return emitError() <<
"port " << name <<
" has wrong type, got " << type
2122 <<
", expected " << expectedType;
2129 auto n = classOp.getNumPorts();
2130 SmallVector<ClassElement> elements;
2131 elements.reserve(n);
2132 for (
size_t i = 0; i < n; ++i)
2133 elements.push_back({classOp.getPortNameAttr(i), classOp.getPortType(i),
2134 classOp.getPortDirection(i)});
2135 auto name = FlatSymbolRefAttr::get(classOp.getNameAttr());
2136 return ClassType::get(name, elements);
2139template <
typename OpTy>
2141 bool hasSSAIdentifiers) {
2142 auto *context = result.getContext();
2143 auto &builder = parser.getBuilder();
2144 auto &properties = result.getOrAddProperties<
typename OpTy::Properties>();
2148 (void)mlir::impl::parseOptionalVisibilityKeyword(parser, result.attributes);
2151 StringAttr nameAttr;
2152 if (parser.parseSymbolName(nameAttr))
2154 properties.setSymName(nameAttr);
2157 SmallVector<OpAsmParser::Argument> entryArgs;
2158 SmallVector<Direction, 4> portDirections;
2159 SmallVector<Attribute, 4> portNames;
2160 SmallVector<Attribute, 4> portTypes;
2161 SmallVector<Attribute, 4> portAnnotations;
2162 SmallVector<Attribute, 4> portSyms;
2163 SmallVector<Attribute, 4> portLocs;
2164 SmallVector<Attribute, 4> domains;
2167 entryArgs, portDirections, portNames, portTypes,
2168 portAnnotations, portSyms, portLocs, domains))
2172 for (
auto annos : portAnnotations)
2173 if (!cast<ArrayAttr>(annos).empty())
2177 if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
2180 assert(portNames.size() == portTypes.size());
2186 properties.setPortDirections(
2190 properties.setPortNames(builder.getArrayAttr(portNames));
2193 properties.setPortTypes(builder.getArrayAttr(portTypes));
2196 FModuleLike::fixupPortSymsArray(portSyms, builder.getContext());
2197 properties.setPortSymbols(builder.getArrayAttr(portSyms));
2200 properties.setPortLocations(ArrayAttr::get(context, portLocs));
2206 auto *bodyRegion = result.addRegion();
2208 if (hasSSAIdentifiers) {
2209 if (parser.parseRegion(*bodyRegion, entryArgs))
2211 if (bodyRegion->empty())
2212 bodyRegion->push_back(
new Block());
2222 StringRef visibilityAttrName = SymbolTable::getVisibilityAttrName();
2223 if (
auto visibility = op->getAttrOfType<StringAttr>(visibilityAttrName))
2224 p << visibility.getValue() <<
' ';
2227 p.printSymbolName(op.getName());
2231 Region ®ion = op->getRegion(0);
2232 Block *body =
nullptr;
2233 if (!region.empty())
2234 body = ®ion.front();
2237 p, body, op.getPortDirectionsAttr(), op.getPortNames(), op.getPortTypes(),
2238 {}, op.getPortSymbols(), op.getPortLocations(), {});
2241 SmallVector<StringRef, 8> omittedAttrs = {
2242 "sym_name",
"portNames",
"portTypes",
"portDirections",
2243 "portSymbols",
"portLocations", visibilityAttrName,
"domainInfo"};
2247 if (!needPortNamesAttr)
2248 omittedAttrs.push_back(
"portNames");
2250 p.printOptionalAttrDictWithKeyword(op->getAttrs(), omittedAttrs);
2253 if (!region.empty()) {
2255 auto printEntryBlockArgs =
false;
2256 auto printBlockTerminators =
false;
2257 p.printRegion(region, printEntryBlockArgs, printBlockTerminators);
2265void ClassOp::build(OpBuilder &builder, OperationState &result, StringAttr name,
2266 ArrayRef<PortInfo> ports) {
2269 [](
const auto &port) {
return port.annotations.empty(); }) &&
2270 "class ports may not have annotations");
2272 buildClass<ClassOp>(builder, result, name, ports);
2275 auto *bodyRegion = result.regions[0].get();
2277 bodyRegion->push_back(body);
2280 for (
auto &elt : ports)
2281 body->addArgument(elt.type, elt.loc);
2284void ClassOp::build(::mlir::OpBuilder &odsBuilder,
2285 ::mlir::OperationState &odsState, Twine name,
2286 mlir::ArrayRef<mlir::StringRef> fieldNames,
2287 mlir::ArrayRef<mlir::Type> fieldTypes) {
2289 SmallVector<PortInfo, 10> ports;
2290 for (
auto [fieldName, fieldType] :
llvm::zip(fieldNames, fieldTypes)) {
2291 ports.emplace_back(odsBuilder.getStringAttr(fieldName +
"_in"), fieldType,
2293 ports.emplace_back(odsBuilder.getStringAttr(fieldName), fieldType,
2296 build(odsBuilder, odsState, odsBuilder.getStringAttr(name), ports);
2298 auto &body = odsState.regions[0]->getBlocks().front();
2299 auto prevLoc = odsBuilder.saveInsertionPoint();
2300 odsBuilder.setInsertionPointToEnd(&body);
2301 auto args = body.getArguments();
2302 auto loc = odsState.location;
2303 for (
unsigned i = 0, e = ports.size(); i != e; i += 2)
2304 PropAssignOp::create(odsBuilder, loc, args[i + 1], args[i]);
2306 odsBuilder.restoreInsertionPoint(prevLoc);
2308void ClassOp::print(OpAsmPrinter &p) {
2312ParseResult ClassOp::parse(OpAsmParser &parser, OperationState &result) {
2313 auto hasSSAIdentifiers =
true;
2314 return parseClassLike<ClassOp>(parser, result, hasSSAIdentifiers);
2317LogicalResult ClassOp::verify() {
2319 auto type = operand.getType();
2320 if (!isa<PropertyType>(type)) {
2321 emitOpError(
"ports on a class must be properties");
2330ClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2334void ClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2339SmallVector<PortInfo> ClassOp::getPorts() {
2340 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2343void ClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2344 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2348void ClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2349 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2352Convention ClassOp::getConvention() {
return Convention::Internal; }
2354ConventionAttr ClassOp::getConventionAttr() {
2355 return ConventionAttr::get(getContext(), getConvention());
2358ArrayAttr ClassOp::getParameters() {
return {}; }
2360ArrayAttr ClassOp::getPortAnnotationsAttr() {
2361 return ArrayAttr::get(getContext(), {});
2364ArrayRef<Attribute> ClassOp::getPortAnnotations() {
return {}; }
2366void ClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2367 llvm_unreachable(
"classes do not support annotations");
2370ArrayAttr ClassOp::getLayersAttr() {
return ArrayAttr::get(getContext(), {}); }
2372ArrayRef<Attribute> ClassOp::getLayers() {
return {}; }
2374SmallVector<::circt::hw::PortInfo> ClassOp::getPortList() {
2375 return ::getPortListImpl(*
this);
2379 return ::getPortImpl(*
this, idx);
2382BlockArgument ClassOp::getArgument(
size_t portNumber) {
2386bool ClassOp::canDiscardOnUseEmpty() {
2397void ExtClassOp::build(OpBuilder &builder, OperationState &result,
2398 StringAttr name, ArrayRef<PortInfo> ports) {
2401 [](
const auto &port) {
return port.annotations.empty(); }) &&
2402 "class ports may not have annotations");
2403 buildClass<ClassOp>(builder, result, name, ports);
2406void ExtClassOp::print(OpAsmPrinter &p) {
2410ParseResult ExtClassOp::parse(OpAsmParser &parser, OperationState &result) {
2411 auto hasSSAIdentifiers =
false;
2412 return parseClassLike<ExtClassOp>(parser, result, hasSSAIdentifiers);
2416ExtClassOp::verifySymbolUses(::mlir::SymbolTableCollection &symbolTable) {
2420void ExtClassOp::getAsmBlockArgumentNames(mlir::Region ®ion,
2425SmallVector<PortInfo> ExtClassOp::getPorts() {
2426 return ::getPortImpl(cast<FModuleLike>((Operation *)*
this));
2429void ExtClassOp::erasePorts(
const llvm::BitVector &portIndices) {
2430 ::erasePorts(cast<FModuleLike>((Operation *)*
this), portIndices);
2433void ExtClassOp::insertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2434 ::insertPorts(cast<FModuleLike>((Operation *)*
this), ports);
2437Convention ExtClassOp::getConvention() {
return Convention::Internal; }
2439ConventionAttr ExtClassOp::getConventionAttr() {
2440 return ConventionAttr::get(getContext(), getConvention());
2443ArrayAttr ExtClassOp::getLayersAttr() {
2444 return ArrayAttr::get(getContext(), {});
2447ArrayRef<Attribute> ExtClassOp::getLayers() {
return {}; }
2449ArrayAttr ExtClassOp::getParameters() {
return {}; }
2451ArrayAttr ExtClassOp::getPortAnnotationsAttr() {
2452 return ArrayAttr::get(getContext(), {});
2455ArrayRef<Attribute> ExtClassOp::getPortAnnotations() {
return {}; }
2457void ExtClassOp::setPortAnnotationsAttr(ArrayAttr annotations) {
2458 llvm_unreachable(
"classes do not support annotations");
2461SmallVector<::circt::hw::PortInfo> ExtClassOp::getPortList() {
2462 return ::getPortListImpl(*
this);
2466 return ::getPortImpl(*
this, idx);
2469bool ExtClassOp::canDiscardOnUseEmpty() {
2480void InstanceOp::build(
2481 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2482 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2483 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2484 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2485 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2486 bool lowerToBind,
bool doNotPrint, StringAttr innerSym) {
2487 build(builder, result, resultTypes, moduleName, name, nameKind,
2488 portDirections, portNames, domainInfo, annotations, portAnnotations,
2489 layers, lowerToBind, doNotPrint,
2490 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2493void InstanceOp::build(
2494 OpBuilder &builder, OperationState &result, TypeRange resultTypes,
2495 StringRef moduleName, StringRef name, NameKindEnum nameKind,
2496 ArrayRef<Direction> portDirections, ArrayRef<Attribute> portNames,
2497 ArrayRef<Attribute> domainInfo, ArrayRef<Attribute> annotations,
2498 ArrayRef<Attribute> portAnnotations, ArrayRef<Attribute> layers,
2499 bool lowerToBind,
bool doNotPrint, hw::InnerSymAttr innerSym) {
2500 result.addTypes(resultTypes);
2501 result.getOrAddProperties<Properties>().setModuleName(
2502 SymbolRefAttr::get(builder.getContext(), moduleName));
2503 result.getOrAddProperties<Properties>().setName(builder.getStringAttr(name));
2504 result.getOrAddProperties<Properties>().setPortDirections(
2506 result.getOrAddProperties<Properties>().setPortNames(
2507 builder.getArrayAttr(portNames));
2509 if (domainInfo.empty()) {
2510 SmallVector<Attribute, 16> domainInfoVec(resultTypes.size(),
2511 builder.getArrayAttr({}));
2512 result.getOrAddProperties<Properties>().setDomainInfo(
2513 builder.getArrayAttr(domainInfoVec));
2515 assert(domainInfo.size() == resultTypes.size());
2516 result.getOrAddProperties<Properties>().setDomainInfo(
2517 builder.getArrayAttr(domainInfo));
2520 result.getOrAddProperties<Properties>().setAnnotations(
2521 builder.getArrayAttr(annotations));
2522 result.getOrAddProperties<Properties>().setLayers(
2523 builder.getArrayAttr(layers));
2525 result.getOrAddProperties<Properties>().setLowerToBind(
2526 builder.getUnitAttr());
2528 result.getOrAddProperties<Properties>().setDoNotPrint(
2529 builder.getUnitAttr());
2531 result.getOrAddProperties<Properties>().setInnerSym(innerSym);
2533 result.getOrAddProperties<Properties>().setNameKind(
2534 NameKindEnumAttr::get(builder.getContext(), nameKind));
2536 if (portAnnotations.empty()) {
2537 SmallVector<Attribute, 16> portAnnotationsVec(resultTypes.size(),
2538 builder.getArrayAttr({}));
2539 result.getOrAddProperties<Properties>().setPortAnnotations(
2540 builder.getArrayAttr(portAnnotationsVec));
2542 assert(portAnnotations.size() == resultTypes.size());
2543 result.getOrAddProperties<Properties>().setPortAnnotations(
2544 builder.getArrayAttr(portAnnotations));
2548void InstanceOp::build(OpBuilder &builder, OperationState &result,
2549 FModuleLike module, StringRef name,
2550 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2551 ArrayRef<Attribute> portAnnotations,
bool lowerToBind,
2552 bool doNotPrint, hw::InnerSymAttr innerSym) {
2555 SmallVector<Type> resultTypes;
2556 resultTypes.reserve(module.getNumPorts());
2558 module.getPortTypes(), std::back_inserter(resultTypes),
2559 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2564 ArrayAttr portAnnotationsAttr;
2565 if (portAnnotations.empty()) {
2566 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2567 resultTypes.size(), builder.getArrayAttr({})));
2569 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2571 ArrayAttr domainInfoAttr =
module.getDomainInfoAttr();
2572 if (domainInfoAttr.empty()) {
2573 domainInfoAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2574 resultTypes.size(), builder.getArrayAttr({})));
2578 builder, result, resultTypes,
2579 SymbolRefAttr::get(builder.getContext(), module.getModuleNameAttr()),
2580 builder.getStringAttr(name),
2581 NameKindEnumAttr::get(builder.getContext(), nameKind),
2582 module.getPortDirectionsAttr(), module.getPortNamesAttr(), domainInfoAttr,
2583 builder.getArrayAttr(annotations), portAnnotationsAttr,
2584 module.getLayersAttr(), lowerToBind ? builder.getUnitAttr() : UnitAttr(),
2585 doNotPrint ? builder.getUnitAttr() : UnitAttr(), innerSym);
2588void InstanceOp::build(OpBuilder &builder, OperationState &odsState,
2589 ArrayRef<PortInfo> ports, StringRef moduleName,
2590 StringRef name, NameKindEnum nameKind,
2591 ArrayRef<Attribute> annotations,
2592 ArrayRef<Attribute> layers,
bool lowerToBind,
2593 bool doNotPrint, hw::InnerSymAttr innerSym) {
2595 SmallVector<Type> newResultTypes;
2596 SmallVector<Direction> newPortDirections;
2597 SmallVector<Attribute> newPortNames;
2598 SmallVector<Attribute> newPortAnnotations;
2599 SmallVector<Attribute> newDomainInfo;
2600 for (
auto &p : ports) {
2601 newResultTypes.push_back(p.type);
2602 newPortDirections.push_back(p.direction);
2603 newPortNames.push_back(p.name);
2604 newPortAnnotations.push_back(p.annotations.getArrayAttr());
2606 newDomainInfo.push_back(p.domains);
2608 newDomainInfo.push_back(builder.getArrayAttr({}));
2611 return build(builder, odsState, newResultTypes, moduleName, name, nameKind,
2612 newPortDirections, newPortNames, newDomainInfo, annotations,
2613 newPortAnnotations, layers, lowerToBind, doNotPrint, innerSym);
2616LogicalResult InstanceOp::verify() {
2619 SmallVector<SymbolRefAttr> missingLayers;
2620 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
2622 missingLayers.push_back(layer);
2624 if (missingLayers.empty())
2628 emitOpError(
"ambient layers are insufficient to instantiate module");
2629 auto ¬e = diag.attachNote();
2630 note <<
"missing layer requirements: ";
2631 interleaveComma(missingLayers, note);
2637InstanceOp InstanceOp::erasePorts(OpBuilder &builder,
2638 const llvm::BitVector &portIndices) {
2639 assert(portIndices.size() >= getNumResults() &&
2640 "portIndices is not at least as large as getNumResults()");
2642 if (portIndices.none())
2645 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
2646 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
2647 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
2649 SmallVector<Attribute> newPortNames =
2651 SmallVector<Attribute> newPortAnnotations =
2653 ArrayAttr newDomainInfo =
2657 auto newOp = InstanceOp::create(
2658 builder,
getLoc(), newResultTypes, getModuleName(),
getName(),
2659 getNameKind(), newPortDirections, newPortNames, newDomainInfo.getValue(),
2660 getAnnotations().getValue(), newPortAnnotations, getLayers(),
2661 getLowerToBind(), getDoNotPrint(), getInnerSymAttr());
2663 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
2664 oldIdx != numOldPorts; ++oldIdx) {
2665 if (portIndices.test(oldIdx)) {
2666 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
2669 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
2677 if (
auto outputFile = (*this)->getAttr(
"output_file"))
2678 newOp->setAttr(
"output_file", outputFile);
2683ArrayAttr InstanceOp::getPortAnnotation(
unsigned portIdx) {
2684 assert(portIdx < getNumResults() &&
2685 "index should be smaller than result number");
2686 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
2689void InstanceOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
2690 assert(annotations.size() == getNumResults() &&
2691 "number of annotations is not equal to result number");
2692 (*this)->setAttr(
"portAnnotations",
2693 ArrayAttr::get(getContext(), annotations));
2696ArrayAttr InstanceOp::getPortDomain(
unsigned portIdx) {
2697 assert(portIdx < getNumResults() &&
2698 "index should be smaller than result number");
2699 return cast<ArrayAttr>(getDomainInfo()[portIdx]);
2703InstanceOp::cloneAndInsertPorts(ArrayRef<std::pair<unsigned, PortInfo>> ports) {
2704 auto portSize = ports.size();
2705 auto newPortCount = getNumResults() + portSize;
2706 SmallVector<Direction> newPortDirections;
2707 newPortDirections.reserve(newPortCount);
2708 SmallVector<Attribute> newPortNames;
2709 newPortNames.reserve(newPortCount);
2710 SmallVector<Type> newPortTypes;
2711 newPortTypes.reserve(newPortCount);
2712 SmallVector<Attribute> newPortAnnos;
2713 newPortAnnos.reserve(newPortCount);
2714 SmallVector<Attribute> newDomainInfo;
2715 newDomainInfo.reserve(newPortCount);
2716 SmallVector<unsigned> numInserted;
2717 numInserted.resize(getNumResults());
2719 unsigned oldIndex = 0;
2720 unsigned newIndex = 0;
2721 while (oldIndex + newIndex < newPortCount) {
2723 if (newIndex < portSize && ports[newIndex].first == oldIndex) {
2724 auto &newPort = ports[newIndex].second;
2725 newPortDirections.push_back(newPort.direction);
2726 newPortNames.push_back(newPort.name);
2727 newPortTypes.push_back(newPort.type);
2728 newPortAnnos.push_back(newPort.annotations.getArrayAttr());
2731 newPort.domains ? newPort.domains : ArrayAttr::
get(getContext(), {}),
2733 if (oldIndex < getNumResults())
2734 numInserted[oldIndex] += 1;
2738 newPortDirections.push_back(getPortDirection(oldIndex));
2739 newPortNames.push_back(getPortName(oldIndex));
2740 newPortTypes.push_back(getType(oldIndex));
2741 newPortAnnos.push_back(getPortAnnotation(oldIndex));
2742 newDomainInfo.push_back(getDomainInfo()[oldIndex]);
2744 numInserted[oldIndex] = 0;
2746 numInserted[oldIndex] += numInserted[oldIndex - 1];
2752 OpBuilder builder(*
this);
2753 return InstanceOp::create(
2754 builder,
getLoc(), newPortTypes, getModuleName(),
getName(),
2755 getNameKind(), newPortDirections, newPortNames, newDomainInfo,
2756 getAnnotations().getValue(), newPortAnnos, getLayers(), getLowerToBind(),
2757 getDoNotPrint(), getInnerSymAttr());
2760LogicalResult InstanceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
2762 getModuleNameAttr());
2765StringRef InstanceOp::getInstanceName() {
return getName(); }
2767StringAttr InstanceOp::getInstanceNameAttr() {
return getNameAttr(); }
2769void InstanceOp::print(OpAsmPrinter &p) {
2772 p.printKeywordOrString(
getName());
2773 if (
auto attr = getInnerSymAttr()) {
2775 p.printSymbolName(attr.getSymName());
2777 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2778 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2781 SmallVector<StringRef, 10> omittedAttrs = {
2782 "moduleName",
"name",
"portDirections",
2783 "portNames",
"portTypes",
"portAnnotations",
2784 "inner_sym",
"nameKind",
"domainInfo"};
2785 if (getAnnotations().
empty())
2786 omittedAttrs.push_back(
"annotations");
2787 if (getLayers().
empty())
2788 omittedAttrs.push_back(
"layers");
2789 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2793 p.printSymbolName(getModuleName());
2796 SmallVector<Attribute> portTypes;
2797 portTypes.reserve(getNumResults());
2798 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2802 getPortNames().getValue(), portTypes,
2803 getPortAnnotations().getValue(), {}, {},
2804 getDomainInfo().getValue());
2807ParseResult InstanceOp::parse(OpAsmParser &parser, OperationState &result) {
2808 auto *context = parser.getContext();
2809 auto &properties = result.getOrAddProperties<Properties>();
2812 hw::InnerSymAttr innerSymAttr;
2813 FlatSymbolRefAttr moduleName;
2814 SmallVector<OpAsmParser::Argument> entryArgs;
2815 SmallVector<Direction, 4> portDirections;
2816 SmallVector<Attribute, 4> portNames;
2817 SmallVector<Attribute, 4> portTypes;
2818 SmallVector<Attribute, 4> portAnnotations;
2819 SmallVector<Attribute, 4> portSyms;
2820 SmallVector<Attribute, 4> portLocs;
2821 SmallVector<Attribute, 4> domains;
2822 NameKindEnumAttr nameKind;
2824 if (parser.parseKeywordOrString(&name))
2826 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
2827 if (parser.parseCustomAttributeWithFallback(
2828 innerSymAttr, ::mlir::Type{},
2830 result.attributes)) {
2831 return ::mlir::failure();
2835 parser.parseOptionalAttrDict(result.attributes) ||
2836 parser.parseAttribute(moduleName) ||
2839 entryArgs, portDirections, portNames, portTypes,
2840 portAnnotations, portSyms, portLocs, domains))
2846 properties.setModuleName(moduleName);
2847 properties.setName(StringAttr::get(context, name));
2848 properties.setNameKind(nameKind);
2849 properties.setPortDirections(
2851 properties.setPortNames(ArrayAttr::get(context, portNames));
2852 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
2856 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
2857 properties.setLayers(parser.getBuilder().getArrayAttr({}));
2860 properties.setDomainInfo(ArrayAttr::get(context, domains));
2863 result.types.reserve(portTypes.size());
2865 portTypes, std::back_inserter(result.types),
2866 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
2871void InstanceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
2876 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
2877 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
2881std::optional<size_t> InstanceOp::getTargetResultIndex() {
2883 return std::nullopt;
2890void InstanceChoiceOp::build(
2891 OpBuilder &builder, OperationState &result, FModuleLike defaultModule,
2892 ArrayRef<std::pair<OptionCaseOp, FModuleLike>> cases, StringRef name,
2893 NameKindEnum nameKind, ArrayRef<Attribute> annotations,
2894 ArrayRef<Attribute> portAnnotations, StringAttr innerSym) {
2896 SmallVector<Type> resultTypes;
2897 for (Attribute portType : defaultModule.getPortTypes())
2898 resultTypes.push_back(cast<TypeAttr>(portType).getValue());
2901 ArrayAttr portAnnotationsAttr;
2902 if (portAnnotations.empty()) {
2903 portAnnotationsAttr = builder.getArrayAttr(SmallVector<Attribute, 16>(
2904 resultTypes.size(), builder.getArrayAttr({})));
2906 portAnnotationsAttr = builder.getArrayAttr(portAnnotations);
2910 SmallVector<Attribute> moduleNames, caseNames;
2911 moduleNames.push_back(SymbolRefAttr::get(defaultModule.getModuleNameAttr()));
2912 for (
auto [caseOption, caseModule] : cases) {
2913 auto caseGroup = caseOption->getParentOfType<OptionOp>();
2914 caseNames.push_back(SymbolRefAttr::get(caseGroup.getSymNameAttr(),
2915 {SymbolRefAttr::get(caseOption)}));
2916 moduleNames.push_back(SymbolRefAttr::get(caseModule.getModuleNameAttr()));
2920 builder, result, resultTypes, builder.getArrayAttr(moduleNames),
2921 builder.getArrayAttr(caseNames), builder.getStringAttr(name),
2922 NameKindEnumAttr::get(builder.getContext(), nameKind),
2923 defaultModule.getPortDirectionsAttr(), defaultModule.getPortNamesAttr(),
2924 defaultModule.getDomainInfoAttr(), builder.getArrayAttr(annotations),
2925 portAnnotationsAttr, defaultModule.getLayersAttr(),
2926 innerSym ? hw::InnerSymAttr::get(innerSym) :
hw::InnerSymAttr());
2929std::optional<size_t> InstanceChoiceOp::getTargetResultIndex() {
2930 return std::nullopt;
2933void InstanceChoiceOp::print(OpAsmPrinter &p) {
2936 p.printKeywordOrString(
getName());
2937 if (
auto attr = getInnerSymAttr()) {
2939 p.printSymbolName(attr.getSymName());
2941 if (getNameKindAttr().getValue() != NameKindEnum::DroppableName)
2942 p <<
' ' << stringifyNameKindEnum(getNameKindAttr().getValue());
2945 SmallVector<StringRef, 11> omittedAttrs = {
2946 "moduleNames",
"caseNames",
"name",
2947 "portDirections",
"portNames",
"portTypes",
2948 "portAnnotations",
"inner_sym",
"nameKind",
2950 if (getAnnotations().
empty())
2951 omittedAttrs.push_back(
"annotations");
2952 if (getLayers().
empty())
2953 omittedAttrs.push_back(
"layers");
2954 p.printOptionalAttrDict((*this)->getAttrs(), omittedAttrs);
2959 auto moduleNames = getModuleNamesAttr();
2960 auto caseNames = getCaseNamesAttr();
2962 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[0]).getValue());
2964 p <<
" alternatives ";
2966 cast<SymbolRefAttr>(caseNames[0]).getRootReference().getValue());
2968 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
2972 auto symbol = cast<SymbolRefAttr>(caseNames[i]);
2973 p.printSymbolName(symbol.getNestedReferences()[0].getValue());
2975 p.printSymbolName(cast<FlatSymbolRefAttr>(moduleNames[i + 1]).getValue());
2981 SmallVector<Attribute> portTypes;
2982 portTypes.reserve(getNumResults());
2983 llvm::transform(getResultTypes(), std::back_inserter(portTypes),
2986 getPortNames().getValue(), portTypes,
2987 getPortAnnotations().getValue(), {}, {},
2988 getDomainInfo().getValue());
2991ParseResult InstanceChoiceOp::parse(OpAsmParser &parser,
2992 OperationState &result) {
2993 auto *context = parser.getContext();
2994 auto &properties = result.getOrAddProperties<Properties>();
2997 hw::InnerSymAttr innerSymAttr;
2998 SmallVector<Attribute> moduleNames;
2999 SmallVector<Attribute> caseNames;
3000 SmallVector<OpAsmParser::Argument> entryArgs;
3001 SmallVector<Direction, 4> portDirections;
3002 SmallVector<Attribute, 4> portNames;
3003 SmallVector<Attribute, 4> portTypes;
3004 SmallVector<Attribute, 4> portAnnotations;
3005 SmallVector<Attribute, 4> portSyms;
3006 SmallVector<Attribute, 4> portLocs;
3007 SmallVector<Attribute, 4> domains;
3008 NameKindEnumAttr nameKind;
3010 if (parser.parseKeywordOrString(&name))
3012 if (succeeded(parser.parseOptionalKeyword(
"sym"))) {
3013 if (parser.parseCustomAttributeWithFallback(
3014 innerSymAttr, Type{},
3016 result.attributes)) {
3021 parser.parseOptionalAttrDict(result.attributes))
3024 FlatSymbolRefAttr defaultModuleName;
3025 if (parser.parseAttribute(defaultModuleName))
3027 moduleNames.push_back(defaultModuleName);
3031 FlatSymbolRefAttr optionName;
3032 if (parser.parseKeyword(
"alternatives") ||
3033 parser.parseAttribute(optionName) || parser.parseLBrace())
3036 FlatSymbolRefAttr moduleName;
3037 StringAttr caseName;
3038 while (succeeded(parser.parseOptionalSymbolName(caseName))) {
3039 if (parser.parseArrow() || parser.parseAttribute(moduleName))
3041 moduleNames.push_back(moduleName);
3042 caseNames.push_back(SymbolRefAttr::get(
3043 optionName.getAttr(), {FlatSymbolRefAttr::get(caseName)}));
3044 if (failed(parser.parseOptionalComma()))
3047 if (parser.parseRBrace())
3053 entryArgs, portDirections, portNames, portTypes,
3054 portAnnotations, portSyms, portLocs, domains))
3059 properties.setModuleNames(ArrayAttr::get(context, moduleNames));
3060 properties.setCaseNames(ArrayAttr::get(context, caseNames));
3061 properties.setName(StringAttr::get(context, name));
3062 properties.setNameKind(nameKind);
3063 properties.setPortDirections(
3065 properties.setPortNames(ArrayAttr::get(context, portNames));
3066 properties.setDomainInfo(ArrayAttr::get(context, domains));
3067 properties.setPortAnnotations(ArrayAttr::get(context, portAnnotations));
3071 properties.setAnnotations(parser.getBuilder().getArrayAttr({}));
3072 properties.setLayers(parser.getBuilder().getArrayAttr({}));
3075 result.types.reserve(portTypes.size());
3077 portTypes, std::back_inserter(result.types),
3078 [](Attribute typeAttr) { return cast<TypeAttr>(typeAttr).getValue(); });
3083void InstanceChoiceOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3085 for (
auto [result, name] :
llvm::zip(getResults(), getPortNames()))
3086 setNameFn(result, (base +
"_" + cast<StringAttr>(name).getValue()).str());
3089LogicalResult InstanceChoiceOp::verify() {
3090 if (getCaseNamesAttr().
empty())
3091 return emitOpError() <<
"must have at least one case";
3092 if (getModuleNamesAttr().size() != getCaseNamesAttr().size() + 1)
3093 return emitOpError() <<
"number of referenced modules does not match the "
3094 "number of options";
3099 SmallVector<SymbolRefAttr> missingLayers;
3100 for (
auto layer : getLayersAttr().getAsRange<SymbolRefAttr>())
3102 missingLayers.push_back(layer);
3104 if (missingLayers.empty())
3108 emitOpError(
"ambient layers are insufficient to instantiate module");
3109 auto ¬e = diag.attachNote();
3110 note <<
"missing layer requirements: ";
3111 interleaveComma(missingLayers, note);
3116InstanceChoiceOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3117 auto caseNames = getCaseNamesAttr();
3118 for (
auto moduleName : getModuleNamesAttr()) {
3120 *
this, symbolTable, cast<FlatSymbolRefAttr>(moduleName))))
3124 auto root = cast<SymbolRefAttr>(caseNames[0]).getRootReference();
3125 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3126 auto ref = cast<SymbolRefAttr>(caseNames[i]);
3127 auto refRoot = ref.getRootReference();
3128 if (ref.getRootReference() != root)
3129 return emitOpError() <<
"case " << ref
3130 <<
" is not in the same option group as "
3133 if (!symbolTable.lookupNearestSymbolFrom<OptionOp>(*
this, refRoot))
3134 return emitOpError() <<
"option " << refRoot <<
" does not exist";
3136 if (!symbolTable.lookupNearestSymbolFrom<OptionCaseOp>(*
this, ref))
3137 return emitOpError() <<
"option " << refRoot
3138 <<
" does not contain option case " << ref;
3145InstanceChoiceOp::getTargetOrDefaultAttr(OptionCaseOp option) {
3146 auto caseNames = getCaseNamesAttr();
3147 for (
size_t i = 0, n = caseNames.size(); i < n; ++i) {
3148 StringAttr caseSym = cast<SymbolRefAttr>(caseNames[i]).getLeafReference();
3149 if (caseSym == option.getSymName())
3150 return cast<FlatSymbolRefAttr>(getModuleNamesAttr()[i + 1]);
3152 return getDefaultTargetAttr();
3155SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1>
3156InstanceChoiceOp::getTargetChoices() {
3157 auto caseNames = getCaseNamesAttr();
3158 auto moduleNames = getModuleNamesAttr();
3159 SmallVector<std::pair<SymbolRefAttr, FlatSymbolRefAttr>, 1> choices;
3160 for (
size_t i = 0; i < caseNames.size(); ++i) {
3161 choices.emplace_back(cast<SymbolRefAttr>(caseNames[i]),
3162 cast<FlatSymbolRefAttr>(moduleNames[i + 1]));
3169InstanceChoiceOp::erasePorts(OpBuilder &builder,
3170 const llvm::BitVector &portIndices) {
3171 assert(portIndices.size() >= getNumResults() &&
3172 "portIndices is not at least as large as getNumResults()");
3174 if (portIndices.none())
3177 SmallVector<Type> newResultTypes = removeElementsAtIndices<Type>(
3178 SmallVector<Type>(result_type_begin(), result_type_end()), portIndices);
3179 SmallVector<Direction> newPortDirections = removeElementsAtIndices<Direction>(
3181 SmallVector<Attribute> newPortNames =
3183 SmallVector<Attribute> newPortAnnotations =
3185 ArrayAttr newPortDomains =
3189 auto newOp = InstanceChoiceOp::create(
3190 builder,
getLoc(), newResultTypes, getModuleNames(), getCaseNames(),
3193 ArrayAttr::get(getContext(), newPortNames),
3194 ArrayAttr::get(getContext(), newPortDomains), getAnnotationsAttr(),
3195 ArrayAttr::get(getContext(), newPortAnnotations), getLayers(),
3198 for (
unsigned oldIdx = 0, newIdx = 0, numOldPorts = getNumResults();
3199 oldIdx != numOldPorts; ++oldIdx) {
3200 if (portIndices.test(oldIdx)) {
3201 assert(getResult(oldIdx).use_empty() &&
"removed instance port has uses");
3204 getResult(oldIdx).replaceAllUsesWith(newOp.getResult(newIdx));
3212 if (
auto outputFile = (*this)->getAttr(
"output_file"))
3213 newOp->setAttr(
"output_file", outputFile);
3222ArrayAttr MemOp::getPortAnnotation(
unsigned portIdx) {
3223 assert(portIdx < getNumResults() &&
3224 "index should be smaller than result number");
3225 return cast<ArrayAttr>(getPortAnnotations()[portIdx]);
3228void MemOp::setAllPortAnnotations(ArrayRef<Attribute> annotations) {
3229 assert(annotations.size() == getNumResults() &&
3230 "number of annotations is not equal to result number");
3231 (*this)->setAttr(
"portAnnotations",
3232 ArrayAttr::get(getContext(), annotations));
3236void MemOp::getNumPorts(
size_t &numReadPorts,
size_t &numWritePorts,
3237 size_t &numReadWritePorts,
size_t &numDbgsPorts) {
3240 numReadWritePorts = 0;
3242 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3243 auto portKind = getPortKind(i);
3244 if (portKind == MemOp::PortKind::Debug)
3246 else if (portKind == MemOp::PortKind::Read)
3248 else if (portKind == MemOp::PortKind::Write) {
3251 ++numReadWritePorts;
3256LogicalResult MemOp::verify() {
3260 llvm::SmallDenseSet<Attribute, 8> portNamesSet;
3266 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3267 auto portName = getPortName(i);
3272 BundleType portBundleType =
3273 type_dyn_cast<BundleType>(getResult(i).getType());
3276 if (!portNamesSet.insert(portName).second) {
3277 emitOpError() <<
"has non-unique port name " << portName;
3285 auto elt = getPortNamed(portName);
3287 emitOpError() <<
"could not get port with name " << portName;
3290 auto firrtlType = type_cast<FIRRTLType>(elt.getType());
3293 if (portKind == MemOp::PortKind::Debug &&
3294 !type_isa<RefType>(getResult(i).getType()))
3295 return emitOpError() <<
"has an invalid type on port " << portName
3296 <<
" (expected Read/Write/ReadWrite/Debug)";
3297 if (type_isa<RefType>(firrtlType) && e == 1)
3298 return emitOpError()
3299 <<
"cannot have only one port of debug type. Debug port can only "
3300 "exist alongside other read/write/read-write port";
3305 if (portKind == MemOp::PortKind::Debug) {
3306 auto resType = type_cast<RefType>(getResult(i).getType());
3307 if (!(resType && type_isa<FVectorType>(resType.getType())))
3308 return emitOpError() <<
"debug ports must be a RefType of FVectorType";
3309 dataType = type_cast<FVectorType>(resType.getType()).getElementType();
3311 auto dataTypeOption = portBundleType.getElement(
"data");
3312 if (!dataTypeOption && portKind == MemOp::PortKind::ReadWrite)
3313 dataTypeOption = portBundleType.getElement(
"wdata");
3314 if (!dataTypeOption) {
3315 emitOpError() <<
"has no data field on port " << portName
3316 <<
" (expected to see \"data\" for a read or write "
3317 "port or \"rdata\" for a read/write port)";
3320 dataType = dataTypeOption->type;
3322 if (portKind == MemOp::PortKind::Read) {
3329 emitOpError() <<
"has non-passive data type on port " << portName
3330 <<
" (memory types must be passive)";
3335 if (dataType.containsAnalog()) {
3336 emitOpError() <<
"has a data type that contains an analog type on port "
3338 <<
" (memory types cannot contain analog types)";
3346 getTypeForPort(getDepth(), dataType, portKind,
3347 dataType.isGround() ? getMaskBits() : 0);
3350 auto originalType = getResult(i).getType();
3351 if (originalType != expectedType) {
3352 StringRef portKindName;
3354 case MemOp::PortKind::Read:
3355 portKindName =
"read";
3357 case MemOp::PortKind::Write:
3358 portKindName =
"write";
3360 case MemOp::PortKind::ReadWrite:
3361 portKindName =
"readwrite";
3363 case MemOp::PortKind::Debug:
3364 portKindName =
"dbg";
3367 emitOpError() <<
"has an invalid type for port " << portName
3368 <<
" of determined kind \"" << portKindName
3369 <<
"\" (expected " << expectedType <<
", but got "
3370 << originalType <<
")";
3376 if (oldDataType && oldDataType != dataType) {
3377 emitOpError() <<
"port " << getPortName(i)
3378 <<
" has a different type than port " << getPortName(i - 1)
3379 <<
" (expected " << oldDataType <<
", but got " << dataType
3384 oldDataType = dataType;
3387 auto maskWidth = getMaskBits();
3389 auto dataWidth = getDataType().getBitWidthOrSentinel();
3390 if (dataWidth > 0 && maskWidth > (
size_t)dataWidth)
3391 return emitOpError(
"the mask width cannot be greater than "
3394 if (getPortAnnotations().size() != getNumResults())
3395 return emitOpError(
"the number of result annotations should be "
3396 "equal to the number of results");
3402 return std::max(1U, llvm::Log2_64_Ceil(depth));
3408 PortKind portKind,
size_t maskBits) {
3410 auto *context = dataType.getContext();
3411 if (portKind == PortKind::Debug)
3412 return RefType::get(FVectorType::get(dataType, depth));
3418 maskType = UIntType::get(context, maskBits);
3420 auto getId = [&](StringRef name) -> StringAttr {
3421 return StringAttr::get(context, name);
3424 SmallVector<BundleType::BundleElement, 7> portFields;
3428 portFields.push_back({getId(
"addr"),
false, addressType});
3429 portFields.push_back({getId(
"en"),
false, UIntType::get(context, 1)});
3430 portFields.push_back({getId(
"clk"),
false, ClockType::get(context)});
3433 case PortKind::Read:
3434 portFields.push_back({getId(
"data"),
true, dataType});
3437 case PortKind::Write:
3438 portFields.push_back({getId(
"data"),
false, dataType});
3439 portFields.push_back({getId(
"mask"),
false, maskType});
3442 case PortKind::ReadWrite:
3443 portFields.push_back({getId(
"rdata"),
true, dataType});
3444 portFields.push_back({getId(
"wmode"),
false, UIntType::get(context, 1)});
3445 portFields.push_back({getId(
"wdata"),
false, dataType});
3446 portFields.push_back({getId(
"wmask"),
false, maskType});
3449 llvm::report_fatal_error(
"memory port kind not handled");
3453 return BundleType::get(context, portFields);
3457SmallVector<MemOp::NamedPort> MemOp::getPorts() {
3458 SmallVector<MemOp::NamedPort> result;
3460 for (
size_t i = 0, e = getNumResults(); i != e; ++i) {
3462 auto portType = type_cast<FIRRTLType>(getResult(i).getType());
3469MemOp::PortKind MemOp::getPortKind(StringRef portName) {
3471 type_cast<FIRRTLType>(getPortNamed(portName).getType()));
3475MemOp::PortKind MemOp::getPortKind(
size_t resultNo) {
3477 type_cast<FIRRTLType>(getResult(resultNo).getType()));
3481size_t MemOp::getMaskBits() {
3483 for (
auto res : getResults()) {
3484 if (type_isa<RefType>(res.getType()))
3486 auto firstPortType = type_cast<FIRRTLBaseType>(res.getType());
3493 if (t.name.getValue().contains(
"mask"))
3496 if (type_isa<UIntType>(mType))
3506 assert(getNumResults() != 0 &&
"Mems with no read/write ports are illegal");
3508 if (
auto refType = type_dyn_cast<RefType>(getResult(0).getType()))
3509 return type_cast<FVectorType>(refType.getType()).getElementType();
3510 auto firstPortType = type_cast<FIRRTLBaseType>(getResult(0).getType());
3512 StringRef dataFieldName =
"data";
3514 dataFieldName =
"rdata";
3516 return type_cast<BundleType>(firstPortType.getPassiveType())
3517 .getElementType(dataFieldName);
3520StringAttr MemOp::getPortName(
size_t resultNo) {
3521 return cast<StringAttr>(getPortNames()[resultNo]);
3525 return type_cast<FIRRTLBaseType>(getResults()[resultNo].getType());
3528Value MemOp::getPortNamed(StringAttr name) {
3529 auto namesArray = getPortNames();
3530 for (
size_t i = 0, e = namesArray.size(); i != e; ++i) {
3531 if (namesArray[i] == name) {
3532 assert(i < getNumResults() &&
" names array out of sync with results");
3533 return getResult(i);
3542 size_t numReadPorts = 0;
3543 size_t numWritePorts = 0;
3544 size_t numReadWritePorts = 0;
3546 SmallVector<int32_t> writeClockIDs;
3548 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
3549 auto portKind = op.getPortKind(i);
3550 if (portKind == MemOp::PortKind::Read)
3552 else if (portKind == MemOp::PortKind::Write) {
3553 for (
auto *a : op.getResult(i).getUsers()) {
3554 auto subfield = dyn_cast<SubfieldOp>(a);
3555 if (!subfield || subfield.getFieldIndex() != 2)
3557 auto clockPort = a->getResult(0);
3558 for (
auto *b : clockPort.getUsers()) {
3559 if (
auto connect = dyn_cast<FConnectLike>(b)) {
3560 if (
connect.getDest() == clockPort) {
3563 connect.getSrc(),
true,
true,
true),
3565 if (result.second) {
3566 writeClockIDs.push_back(numWritePorts);
3568 writeClockIDs.push_back(result.first->second);
3577 ++numReadWritePorts;
3584 op.emitError(
"'firrtl.mem' should have simple type and known width");
3585 MemoryInitAttr init = op->getAttrOfType<MemoryInitAttr>(
"init");
3587 if (op->hasAttr(
"modName"))
3588 modName = op->getAttrOfType<StringAttr>(
"modName");
3590 SmallString<8> clocks;
3591 for (
auto a : writeClockIDs)
3592 clocks.
append(Twine((char)(a +
'a')).str());
3593 SmallString<32> initStr;
3598 for (
auto c : init.getFilename().getValue())
3599 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') ||
3600 (c >=
'0' && c <=
'9'))
3601 initStr.push_back(c);
3602 initStr.push_back(
'_');
3603 initStr.push_back(init.getIsBinary() ?
't' :
'f');
3604 initStr.push_back(
'_');
3605 initStr.push_back(init.getIsInline() ?
't' :
'f');
3607 modName = StringAttr::get(
3610 "{0}FIRRTLMem_{1}_{2}_{3}_{4}_{5}_{6}_{7}_{8}_{9}_{10}{11}{12}",
3611 op.getPrefix().value_or(
""), numReadPorts, numWritePorts,
3612 numReadWritePorts, (
size_t)width, op.getDepth(),
3613 op.getReadLatency(), op.getWriteLatency(), op.getMaskBits(),
3614 (
unsigned)op.getRuw(), (
unsigned)seq::WUW::PortOrder,
3615 clocks.empty() ?
"" :
"_" + clocks, init ? initStr.str() :
""));
3617 return {numReadPorts,
3622 op.getReadLatency(),
3623 op.getWriteLatency(),
3625 *seq::symbolizeRUW(
unsigned(op.getRuw())),
3626 seq::WUW::PortOrder,
3629 op.getMaskBits() > 1,
3635void MemOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3640 for (
size_t i = 0, e = (*this)->getNumResults(); i != e; ++i) {
3641 setNameFn(getResult(i), (base +
"_" + getPortNameStr(i)).str());
3645std::optional<size_t> MemOp::getTargetResultIndex() {
3647 return std::nullopt;
3655 OpAsmSetValueNameFn setNameFn) {
3658 setNameFn(op.getDataRaw(), name);
3659 if (op.isForceable())
3660 setNameFn(op.getDataRef(), (name +
"_ref").str());
3663void NodeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3667LogicalResult NodeOp::inferReturnTypes(
3668 mlir::MLIRContext *context, std::optional<mlir::Location> location,
3669 ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
3670 ::mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
3671 ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
3672 if (operands.empty())
3674 Adaptor adaptor(operands, attributes, properties, regions);
3675 inferredReturnTypes.push_back(adaptor.getInput().getType());
3676 if (adaptor.getForceable()) {
3678 true, adaptor.getInput().getType());
3679 if (!forceableType) {
3681 ::mlir::emitError(*location,
"cannot force a node of type ")
3682 << operands[0].getType();
3685 inferredReturnTypes.push_back(forceableType);
3690std::optional<size_t> NodeOp::getTargetResultIndex() {
return 0; }
3692void RegOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3696std::optional<size_t> RegOp::getTargetResultIndex() {
return 0; }
3698SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3699RegOp::computeDataFlow() {
3704LogicalResult RegResetOp::verify() {
3705 auto reset = getResetValue();
3712 return emitError(
"type mismatch between register ")
3713 << regType <<
" and reset value " << resetType;
3718std::optional<size_t> RegResetOp::getTargetResultIndex() {
return 0; }
3720void RegResetOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3729FormalOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3730 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3732 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3734 if (!isa<FModuleLike>(op)) {
3735 auto d = emitOpError() <<
"target " << getModuleNameAttr()
3736 <<
" is not a module";
3737 d.attachNote(op->getLoc()) <<
"target defined here";
3749SimulationOp::verifySymbolUses(mlir::SymbolTableCollection &symbolTable) {
3750 auto *op = symbolTable.lookupNearestSymbolFrom(*
this, getModuleNameAttr());
3752 return emitOpError() <<
"targets unknown module " << getModuleNameAttr();
3754 auto complain = [&] {
3755 auto d = emitOpError() <<
"target " << getModuleNameAttr() <<
" ";
3756 d.attachNote(op->getLoc()) <<
"target defined here";
3760 auto module = dyn_cast<FModuleLike>(op);
3762 return complain() <<
"is not a module";
3764 auto numPorts =
module.getPortDirections().size();
3766 return complain() <<
"must have 4 ports, got " << numPorts <<
" instead";
3768 auto checkPort = [&](
unsigned idx, StringRef expName,
Direction expDir,
3769 llvm::function_ref<bool(Type)> checkType,
3770 StringRef expType) {
3771 auto name =
module.getPortNameAttr(idx);
3772 if (name != expName) {
3773 complain() <<
"port " << idx <<
" must be called \"" << expName
3774 <<
"\", got " << name <<
" instead";
3777 if (
auto dir = module.getPortDirection(idx); dir != expDir) {
3781 complain() <<
"port " << name <<
" must be " << stringify(expDir)
3782 <<
", got " << stringify(dir) <<
" instead";
3785 if (
auto type = module.getPortType(idx); !checkType(type)) {
3786 complain() <<
"port " << name <<
" must be a '!firrtl." << expType
3787 <<
"', got " << type <<
" instead";
3793 auto isClock = [](Type type) {
return isa<ClockType>(type); };
3794 auto isBool = [](Type type) {
3795 if (
auto uintType = dyn_cast<UIntType>(type))
3796 return uintType.getWidth() == 1;
3799 return success(checkPort(0,
"clock",
Direction::In, isClock,
"clock") &&
3809void WireOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3813SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
3814RegResetOp::computeDataFlow() {
3819std::optional<size_t> WireOp::getTargetResultIndex() {
return 0; }
3821LogicalResult WireOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3822 auto refType = type_dyn_cast<RefType>(getType(0));
3827 refType,
getLoc(), getOperation()->getParentOfType<CircuitOp>(),
3828 symbolTable, Twine(
"'") + getOperationName() +
"' op is");
3835LogicalResult ContractOp::verify() {
3836 if (getBody().getArgumentTypes() != getInputs().getType())
3837 return emitOpError(
"result types and region argument types must match");
3845void ObjectOp::build(OpBuilder &builder, OperationState &state, ClassLike klass,
3847 build(builder, state, klass.getInstanceType(),
3848 StringAttr::get(builder.getContext(), name));
3851LogicalResult ObjectOp::verify() {
return success(); }
3853LogicalResult ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
3854 auto circuitOp = getOperation()->getParentOfType<CircuitOp>();
3855 auto classType = getType();
3856 auto className = classType.getNameAttr();
3859 auto classOp = dyn_cast_or_null<ClassLike>(
3860 symbolTable.lookupSymbolIn(circuitOp, className));
3862 return emitOpError() <<
"references unknown class " << className;
3865 if (failed(classOp.verifyType(classType, [&]() { return emitOpError(); })))
3871StringAttr ObjectOp::getClassNameAttr() {
3872 return getType().getNameAttr().getAttr();
3875StringRef ObjectOp::getClassName() {
return getType().getName(); }
3877ClassLike ObjectOp::getReferencedClass(
const SymbolTable &symbolTable) {
3878 auto symRef = getType().getNameAttr();
3879 return symbolTable.lookup<ClassLike>(symRef.getLeafReference());
3882Operation *ObjectOp::getReferencedOperation(
const SymbolTable &symtbl) {
3883 return getReferencedClass(symtbl);
3886StringRef ObjectOp::getInstanceName() {
return getName(); }
3888StringAttr ObjectOp::getInstanceNameAttr() {
return getNameAttr(); }
3890StringRef ObjectOp::getReferencedModuleName() {
return getClassName(); }
3892StringAttr ObjectOp::getReferencedModuleNameAttr() {
3893 return getClassNameAttr();
3896void ObjectOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
3897 setNameFn(getResult(),
getName());
3904LogicalResult AttachOp::verify() {
3906 std::optional<int32_t> commonWidth;
3907 for (
auto operand : getOperands()) {
3908 auto thisWidth = type_cast<AnalogType>(operand.getType()).getWidth();
3912 commonWidth = thisWidth;
3915 if (commonWidth != thisWidth)
3916 return emitOpError(
"is inavlid as not all known operand widths match");
3923 Value dst = connect->getOperand(0);
3924 Value src = connect->getOperand(1);
3933 if (isa<PropertyType>(src.getType()) ||
3937 auto diag = emitError(connect->getLoc());
3938 diag <<
"connect has invalid flow: the source expression ";
3940 diag <<
"\"" << srcName <<
"\" ";
3941 diag <<
"has " <<
toString(srcFlow) <<
", expected source or duplex flow";
3942 return diag.attachNote(srcRef.getLoc()) <<
"the source was defined here";
3950 auto diag = emitError(connect->getLoc());
3951 diag <<
"connect has invalid flow: the destination expression ";
3953 diag <<
"\"" << dstName <<
"\" ";
3954 diag <<
"has " <<
toString(dstFlow) <<
", expected sink or duplex flow";
3955 return diag.attachNote(dstRef.getLoc())
3956 <<
"the destination was defined here";
3965 bool outerTypeIsConst =
false) {
3966 auto typeIsConst = outerTypeIsConst || type.
isConst();
3971 if (
auto bundleType = type_dyn_cast<BundleType>(type))
3972 return llvm::any_of(bundleType.getElements(), [&](
auto &element) {
3973 return isConstFieldDriven(element.type, isFlip ^ element.isFlip,
3977 if (
auto vectorType = type_dyn_cast<FVectorType>(type))
3989 auto dest = connect.getDest();
3990 auto destType = type_dyn_cast<FIRRTLBaseType>(dest.getType());
3991 auto src = connect.getSrc();
3992 auto srcType = type_dyn_cast<FIRRTLBaseType>(src.getType());
3993 if (!destType || !srcType)
3996 auto destRefinedType = destType;
3997 auto srcRefinedType = srcType;
4002 auto findFieldDeclarationRefiningFieldType =
4004 while (
auto *definingOp = value.getDefiningOp()) {
4005 bool shouldContinue =
true;
4006 TypeSwitch<Operation *>(definingOp)
4007 .Case<SubfieldOp, SubindexOp>([&](
auto op) { value = op.getInput(); })
4008 .Case<SubaccessOp>([&](SubaccessOp op) {
4012 .getElementTypePreservingConst()
4014 originalFieldType = originalFieldType.getConstType(
true);
4015 value = op.getInput();
4017 .Default([&](Operation *) { shouldContinue =
false; });
4018 if (!shouldContinue)
4024 auto destDeclaration =
4025 findFieldDeclarationRefiningFieldType(dest, destRefinedType);
4026 auto srcDeclaration =
4027 findFieldDeclarationRefiningFieldType(src, srcRefinedType);
4029 auto checkConstConditionality = [&](Value value,
FIRRTLBaseType type,
4030 Value declaration) -> LogicalResult {
4031 auto *declarationBlock = declaration.getParentBlock();
4032 auto *block = connect->getBlock();
4033 while (block && block != declarationBlock) {
4034 auto *parentOp = block->getParentOp();
4036 if (
auto whenOp = dyn_cast<WhenOp>(parentOp);
4037 whenOp && !whenOp.getCondition().getType().isConst()) {
4039 return connect.emitOpError()
4040 <<
"assignment to 'const' type " << type
4041 <<
" is dependent on a non-'const' condition";
4042 return connect->emitOpError()
4043 <<
"assignment to nested 'const' member of type " << type
4044 <<
" is dependent on a non-'const' condition";
4047 block = parentOp->getBlock();
4052 auto emitSubaccessError = [&] {
4053 return connect.emitError(
4054 "assignment to non-'const' subaccess of 'const' type is disallowed");
4060 if (destType != destRefinedType)
4061 return emitSubaccessError();
4063 if (failed(checkConstConditionality(dest, destType, destDeclaration)))
4068 if (srcRefinedType.containsConst() &&
4071 if (srcType != srcRefinedType)
4072 return emitSubaccessError();
4073 if (failed(checkConstConditionality(src, srcType, srcDeclaration)))
4080LogicalResult ConnectOp::verify() {
4081 auto dstType = getDest().getType();
4082 auto srcType = getSrc().getType();
4083 auto dstBaseType = type_dyn_cast<FIRRTLBaseType>(dstType);
4084 auto srcBaseType = type_dyn_cast<FIRRTLBaseType>(srcType);
4085 if (!dstBaseType || !srcBaseType) {
4086 if (dstType != srcType)
4087 return emitError(
"may not connect different non-base types");
4090 if (dstBaseType.containsAnalog() || srcBaseType.containsAnalog())
4091 return emitError(
"analog types may not be connected");
4095 return emitError(
"type mismatch between destination ")
4096 << dstBaseType <<
" and source " << srcBaseType;
4101 return emitError(
"destination ")
4102 << dstBaseType <<
" is not as wide as the source " << srcBaseType;
4115LogicalResult MatchingConnectOp::verify() {
4116 if (
auto type = type_dyn_cast<FIRRTLType>(getDest().getType())) {
4117 auto baseType = type_cast<FIRRTLBaseType>(type);
4120 if (baseType && baseType.containsAnalog())
4121 return emitError(
"analog types may not be connected");
4126 "`SameAnonTypeOperands` trait should have already rejected "
4127 "structurally non-equivalent types");
4140LogicalResult RefDefineOp::verify() {
4150 for (
auto *user : getDest().getUsers()) {
4151 if (
auto conn = dyn_cast<FConnectLike>(user);
4152 conn && conn.getDest() == getDest() && conn != *
this)
4153 return emitError(
"destination reference cannot be reused by multiple "
4154 "operations, it can only capture a unique dataflow");
4158 if (
auto *op = getDest().getDefiningOp()) {
4160 if (isa<RefSubOp>(op))
4162 "destination reference cannot be a sub-element of a reference");
4163 if (isa<RefCastOp>(op))
4165 "destination reference cannot be a cast of another reference");
4173 SmallVector<SymbolRefAttr> missingLayers;
4176 "has more layer requirements than destination",
4177 "additional layers required");
4180LogicalResult PropAssignOp::verify() {
4186 for (
auto *user : getDest().getUsers()) {
4187 if (
auto conn = dyn_cast<FConnectLike>(user);
4188 conn && conn.getDest() == getDest() && conn != *
this)
4189 return emitError(
"destination property cannot be reused by multiple "
4190 "operations, it can only capture a unique dataflow");
4196void WhenOp::createElseRegion() {
4197 assert(!hasElseRegion() &&
"already has an else region");
4198 getElseRegion().push_back(
new Block());
4201void WhenOp::build(OpBuilder &builder, OperationState &result, Value condition,
4202 bool withElseRegion, std::function<
void()> thenCtor,
4203 std::function<
void()> elseCtor) {
4204 OpBuilder::InsertionGuard guard(builder);
4205 result.addOperands(condition);
4208 builder.createBlock(result.addRegion());
4213 Region *elseRegion = result.addRegion();
4214 if (withElseRegion) {
4215 builder.createBlock(elseRegion);
4225LogicalResult MatchOp::verify() {
4226 FEnumType type = getInput().getType();
4229 auto numCases = getTags().size();
4230 auto numRegions = getNumRegions();
4231 if (numRegions != numCases)
4232 return emitOpError(
"expected ")
4233 << numRegions <<
" tags but got " << numCases;
4235 auto numTags = type.getNumElements();
4237 SmallDenseSet<int64_t> seen;
4238 for (
const auto &[tag, region] :
llvm::zip(getTags(), getRegions())) {
4239 auto tagIndex = size_t(cast<IntegerAttr>(tag).
getInt());
4242 if (region.getNumArguments() != 1)
4243 return emitOpError(
"region should have exactly one argument");
4246 if (tagIndex >= numTags)
4247 return emitOpError(
"the tag index ")
4248 << tagIndex <<
" is out of the range of valid tags in " << type;
4251 auto [it, inserted] = seen.insert(tagIndex);
4253 return emitOpError(
"the tag ") << type.getElementNameAttr(tagIndex)
4254 <<
" is matched more than once";
4257 auto expectedType = type.getElementTypePreservingConst(tagIndex);
4258 auto regionType = region.getArgument(0).getType();
4259 if (regionType != expectedType)
4260 return emitOpError(
"region type ")
4261 << regionType <<
" does not match the expected type "
4266 for (
size_t i = 0, e = type.getNumElements(); i < e; ++i)
4267 if (!seen.contains(i))
4268 return emitOpError(
"missing case for tag ") << type.getElementNameAttr(i);
4273void MatchOp::print(OpAsmPrinter &p) {
4274 auto input = getInput();
4275 FEnumType type = input.getType();
4276 auto regions = getRegions();
4277 p <<
" " << input <<
" : " << type;
4278 SmallVector<StringRef> elided = {
"tags"};
4279 p.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elided);
4282 for (
const auto &[tag, region] :
llvm::zip(getTags(), regions)) {
4285 p.printKeywordOrString(
4286 type.getElementName(cast<IntegerAttr>(tag).getInt()));
4288 p.printRegionArgument(region.front().getArgument(0), {},
4291 p.printRegion(region,
false);
4298ParseResult MatchOp::parse(OpAsmParser &parser, OperationState &result) {
4299 auto *context = parser.getContext();
4300 auto &properties = result.getOrAddProperties<Properties>();
4301 OpAsmParser::UnresolvedOperand input;
4302 if (parser.parseOperand(input) || parser.parseColon())
4305 auto loc = parser.getCurrentLocation();
4307 if (parser.parseType(type))
4309 auto enumType = type_dyn_cast<FEnumType>(type);
4311 return parser.emitError(loc,
"expected enumeration type but got") << type;
4313 if (parser.resolveOperand(input, type, result.operands) ||
4314 parser.parseOptionalAttrDictWithKeyword(result.attributes) ||
4315 parser.parseLBrace())
4318 auto i32Type = IntegerType::get(context, 32);
4319 SmallVector<Attribute> tags;
4322 if (failed(parser.parseOptionalKeyword(
"case")))
4326 auto nameLoc = parser.getCurrentLocation();
4328 OpAsmParser::Argument arg;
4329 auto *region = result.addRegion();
4330 if (parser.parseKeywordOrString(&name) || parser.parseLParen() ||
4331 parser.parseArgument(arg) || parser.parseRParen())
4335 auto index = enumType.getElementIndex(name);
4337 return parser.emitError(nameLoc,
"the tag \"")
4338 << name <<
"\" is not a member of the enumeration " << enumType;
4339 tags.push_back(IntegerAttr::get(i32Type, *index));
4342 arg.type = enumType.getElementTypePreservingConst(*index);
4343 if (parser.parseRegion(*region, arg))
4346 properties.setTags(ArrayAttr::get(context, tags));
4348 return parser.parseRBrace();
4351void MatchOp::build(OpBuilder &builder, OperationState &result, Value input,
4353 MutableArrayRef<std::unique_ptr<Region>> regions) {
4354 auto &properties = result.getOrAddProperties<Properties>();
4355 result.addOperands(input);
4356 properties.setTags(tags);
4357 result.addRegions(regions);
4366 struct IsExprClassifier :
public ExprVisitor<IsExprClassifier, bool> {
4367 bool visitInvalidExpr(Operation *op) {
return false; }
4368 bool visitUnhandledExpr(Operation *op) {
return true; }
4374void InvalidValueOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4377 if (
auto ty = type_dyn_cast<IntType>(getType())) {
4378 const char *base = ty.isSigned() ?
"invalid_si" :
"invalid_ui";
4379 auto width = ty.getWidthOrSentinel();
4383 name = (Twine(base) + Twine(width)).str();
4384 }
else if (
auto ty = type_dyn_cast<AnalogType>(getType())) {
4385 auto width = ty.getWidthOrSentinel();
4387 name =
"invalid_analog";
4389 name = (
"invalid_analog" + Twine(width)).str();
4390 }
else if (type_isa<AsyncResetType>(getType()))
4391 name =
"invalid_asyncreset";
4392 else if (type_isa<ResetType>(getType()))
4393 name =
"invalid_reset";
4394 else if (type_isa<ClockType>(getType()))
4395 name =
"invalid_clock";
4399 setNameFn(getResult(), name);
4402void ConstantOp::print(OpAsmPrinter &p) {
4404 p.printAttributeWithoutType(getValueAttr());
4406 p.printType(getType());
4407 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4410ParseResult ConstantOp::parse(OpAsmParser &parser, OperationState &result) {
4411 auto &properties = result.getOrAddProperties<Properties>();
4414 auto loc = parser.getCurrentLocation();
4415 auto valueResult = parser.parseOptionalInteger(value);
4416 if (!valueResult.has_value())
4417 return parser.emitError(loc,
"expected integer value");
4421 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4422 parser.parseOptionalAttrDict(result.attributes))
4424 result.addTypes(resultType);
4430 if (width > value.getBitWidth()) {
4434 value = value.sext(width);
4435 }
else if (width < value.getBitWidth()) {
4438 unsigned neededBits = value.isNegative() ? value.getSignificantBits()
4439 : value.getActiveBits();
4440 if (width < neededBits)
4441 return parser.emitError(loc,
"constant out of range for result type ")
4443 value = value.trunc(width);
4447 auto intType = parser.getBuilder().getIntegerType(value.getBitWidth(),
4449 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4450 properties.setValue(valueAttr);
4454LogicalResult ConstantOp::verify() {
4458 if (width != -1 && (
int)getValue().
getBitWidth() != width)
4460 "firrtl.constant attribute bitwidth doesn't match return type");
4463 auto attrType = type_cast<IntegerType>(getValueAttr().getType());
4464 if (attrType.isSignless() || attrType.isSigned() != intType.
isSigned())
4465 return emitError(
"firrtl.constant attribute has wrong sign");
4472void ConstantOp::build(OpBuilder &builder, OperationState &result,
IntType type,
4473 const APInt &value) {
4476 assert((width == -1 || (int32_t)value.getBitWidth() == width) &&
4477 "incorrect attribute bitwidth for firrtl.constant");
4480 IntegerAttr::get(type.getContext(), APSInt(value, !type.
isSigned()));
4481 return build(builder, result, type, attr);
4486void ConstantOp::build(OpBuilder &builder, OperationState &result,
4487 const APSInt &value) {
4488 auto attr = IntegerAttr::get(builder.getContext(), value);
4490 IntType::get(builder.getContext(), value.isSigned(), value.getBitWidth());
4491 return build(builder, result, type, attr);
4494void ConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4501 SmallString<32> specialNameBuffer;
4502 llvm::raw_svector_ostream specialName(specialNameBuffer);
4504 getValue().print(specialName, intTy.
isSigned());
4506 specialName << (intTy.
isSigned() ?
"_si" :
"_ui");
4509 specialName << width;
4510 setNameFn(getResult(), specialName.str());
4513void SpecialConstantOp::print(OpAsmPrinter &p) {
4516 p << static_cast<unsigned>(getValue());
4518 p.printType(getType());
4519 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4522ParseResult SpecialConstantOp::parse(OpAsmParser &parser,
4523 OperationState &result) {
4524 auto &properties = result.getOrAddProperties<Properties>();
4528 auto loc = parser.getCurrentLocation();
4529 auto valueResult = parser.parseOptionalInteger(value);
4530 if (!valueResult.has_value())
4531 return parser.emitError(loc,
"expected integer value");
4534 if (value != 0 && value != 1)
4535 return parser.emitError(loc,
"special constants can only be 0 or 1.");
4539 if (failed(*valueResult) || parser.parseColonType(resultType) ||
4540 parser.parseOptionalAttrDict(result.attributes))
4542 result.addTypes(resultType);
4545 auto valueAttr = parser.getBuilder().getBoolAttr(value == 1);
4546 properties.setValue(valueAttr);
4550void SpecialConstantOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
4551 SmallString<32> specialNameBuffer;
4552 llvm::raw_svector_ostream specialName(specialNameBuffer);
4554 specialName << static_cast<unsigned>(getValue());
4555 auto type = getType();
4556 if (type_isa<ClockType>(type)) {
4557 specialName <<
"_clock";
4558 }
else if (type_isa<ResetType>(type)) {
4559 specialName <<
"_reset";
4560 }
else if (type_isa<AsyncResetType>(type)) {
4561 specialName <<
"_asyncreset";
4563 setNameFn(getResult(), specialName.str());
4570 if (type.isGround()) {
4571 if (!isa<IntegerAttr>(attr)) {
4572 op->emitOpError(
"Ground type is not an integer attribute");
4577 auto attrlist = dyn_cast<ArrayAttr>(attr);
4579 op->emitOpError(
"expected array attribute for aggregate constant");
4582 if (
auto array = type_dyn_cast<FVectorType>(type)) {
4583 if (array.getNumElements() != attrlist.size()) {
4584 op->emitOpError(
"array attribute (")
4585 << attrlist.size() <<
") has wrong size for vector constant ("
4586 << array.getNumElements() <<
")";
4589 return llvm::all_of(attrlist, [&array, op](Attribute attr) {
4593 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4594 if (bundle.getNumElements() != attrlist.size()) {
4595 op->emitOpError(
"array attribute (")
4596 << attrlist.size() <<
") has wrong size for bundle constant ("
4597 << bundle.getNumElements() <<
")";
4600 for (
size_t i = 0; i < bundle.getNumElements(); ++i) {
4601 if (bundle.getElement(i).isFlip) {
4602 op->emitOpError(
"Cannot have constant bundle type with flip");
4610 op->emitOpError(
"Unknown aggregate type");
4614LogicalResult AggregateConstantOp::verify() {
4620Attribute AggregateConstantOp::getAttributeFromFieldID(uint64_t fieldID) {
4622 Attribute value = getFields();
4623 while (fieldID != 0) {
4624 if (
auto bundle = type_dyn_cast<BundleType>(type)) {
4625 auto index = bundle.getIndexForFieldID(fieldID);
4626 fieldID -= bundle.getFieldID(index);
4627 type = bundle.getElementType(index);
4628 value = cast<ArrayAttr>(value)[index];
4630 auto vector = type_cast<FVectorType>(type);
4631 auto index = vector.getIndexForFieldID(fieldID);
4632 fieldID -= vector.getFieldID(index);
4633 type = vector.getElementType();
4634 value = cast<ArrayAttr>(value)[index];
4640void FIntegerConstantOp::print(OpAsmPrinter &p) {
4642 p.printAttributeWithoutType(getValueAttr());
4643 p.printOptionalAttrDict((*this)->getAttrs(), {
"value"});
4646ParseResult FIntegerConstantOp::parse(OpAsmParser &parser,
4647 OperationState &result) {
4648 auto *context = parser.getContext();
4649 auto &properties = result.getOrAddProperties<Properties>();
4651 if (parser.parseInteger(value) ||
4652 parser.parseOptionalAttrDict(result.attributes))
4654 result.addTypes(FIntegerType::get(context));
4656 IntegerType::get(context, value.getBitWidth(), IntegerType::Signed);
4657 auto valueAttr = parser.getBuilder().getIntegerAttr(intType, value);
4658 properties.setValue(valueAttr);
4662ParseResult ListCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4663 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 16> operands;
4666 if (parser.parseOperandList(operands) ||
4667 parser.parseOptionalAttrDict(result.attributes) ||
4668 parser.parseColonType(type))
4670 result.addTypes(type);
4672 return parser.resolveOperands(operands, type.getElementType(),
4676void ListCreateOp::print(OpAsmPrinter &p) {
4678 p.printOperands(getElements());
4679 p.printOptionalAttrDict((*this)->getAttrs());
4680 p <<
" : " << getType();
4683LogicalResult ListCreateOp::verify() {
4684 if (getElements().
empty())
4687 auto elementType = getElements().front().getType();
4688 auto listElementType = getType().getElementType();
4690 return emitOpError(
"has elements of type ")
4691 <<
elementType <<
" instead of " << listElementType;
4696LogicalResult BundleCreateOp::verify() {
4697 BundleType resultType = getType();
4698 if (resultType.getNumElements() != getFields().size())
4699 return emitOpError(
"number of fields doesn't match type");
4700 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4702 resultType.getElementTypePreservingConst(i),
4703 type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4704 return emitOpError(
"type of element doesn't match bundle for field ")
4705 << resultType.getElement(i).name;
4710LogicalResult VectorCreateOp::verify() {
4711 FVectorType resultType = getType();
4712 if (resultType.getNumElements() != getFields().size())
4713 return emitOpError(
"number of fields doesn't match type");
4714 auto elemTy = resultType.getElementTypePreservingConst();
4715 for (
size_t i = 0; i < resultType.getNumElements(); ++i)
4717 elemTy, type_cast<FIRRTLBaseType>(getOperand(i).getType())))
4718 return emitOpError(
"type of element doesn't match vector element");
4727LogicalResult FEnumCreateOp::verify() {
4728 FEnumType resultType = getResult().getType();
4729 auto elementIndex = resultType.getElementIndex(
getFieldName());
4731 return emitOpError(
"label ")
4732 <<
getFieldName() <<
" is not a member of the enumeration type "
4735 resultType.getElementTypePreservingConst(*elementIndex),
4736 getInput().getType()))
4737 return emitOpError(
"type of element doesn't match enum element");
4741void FEnumCreateOp::print(OpAsmPrinter &printer) {
4744 printer <<
'(' << getInput() <<
')';
4745 SmallVector<StringRef> elidedAttrs = {
"fieldIndex"};
4746 printer.printOptionalAttrDictWithKeyword((*this)->getAttrs(), elidedAttrs);
4748 printer.printFunctionalType(ArrayRef<Type>{getInput().getType()},
4749 ArrayRef<Type>{getResult().getType()});
4752ParseResult FEnumCreateOp::parse(OpAsmParser &parser, OperationState &result) {
4753 auto *context = parser.getContext();
4754 auto &properties = result.getOrAddProperties<Properties>();
4756 OpAsmParser::UnresolvedOperand input;
4757 std::string fieldName;
4758 mlir::FunctionType functionType;
4759 if (parser.parseKeywordOrString(&fieldName) || parser.parseLParen() ||
4760 parser.parseOperand(input) || parser.parseRParen() ||
4761 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4762 parser.parseType(functionType))
4765 if (functionType.getNumInputs() != 1)
4766 return parser.emitError(parser.getNameLoc(),
"single input type required");
4767 if (functionType.getNumResults() != 1)
4768 return parser.emitError(parser.getNameLoc(),
"single result type required");
4770 auto inputType = functionType.getInput(0);
4771 if (parser.resolveOperand(input, inputType, result.operands))
4774 auto outputType = functionType.getResult(0);
4775 auto enumType = type_dyn_cast<FEnumType>(outputType);
4777 return parser.emitError(parser.getNameLoc(),
4778 "output must be enum type, got ")
4780 auto fieldIndex = enumType.getElementIndex(fieldName);
4782 return parser.emitError(parser.getNameLoc(),
4783 "unknown field " + fieldName +
" in enum type ")
4786 properties.setFieldIndex(
4787 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4789 result.addTypes(enumType);
4798LogicalResult IsTagOp::verify() {
4799 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4800 return emitOpError(
"element index is greater than the number of fields in "
4805void IsTagOp::print(::mlir::OpAsmPrinter &printer) {
4806 printer <<
' ' << getInput() <<
' ';
4808 SmallVector<::llvm::StringRef, 1> elidedAttrs = {
"fieldIndex"};
4809 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4810 printer <<
" : " << getInput().getType();
4813ParseResult IsTagOp::parse(OpAsmParser &parser, OperationState &result) {
4814 auto *context = parser.getContext();
4815 auto &properties = result.getOrAddProperties<Properties>();
4817 OpAsmParser::UnresolvedOperand input;
4818 std::string fieldName;
4820 if (parser.parseOperand(input) || parser.parseKeywordOrString(&fieldName) ||
4821 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4822 parser.parseType(inputType))
4825 if (parser.resolveOperand(input, inputType, result.operands))
4828 auto enumType = type_dyn_cast<FEnumType>(inputType);
4830 return parser.emitError(parser.getNameLoc(),
4831 "input must be enum type, got ")
4833 auto fieldIndex = enumType.getElementIndex(fieldName);
4835 return parser.emitError(parser.getNameLoc(),
4836 "unknown field " + fieldName +
" in enum type ")
4839 properties.setFieldIndex(
4840 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4842 result.addTypes(UIntType::get(context, 1,
false));
4847FIRRTLType IsTagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
4848 OpaqueProperties properties,
4849 mlir::RegionRange regions,
4850 std::optional<Location> loc) {
4851 Adaptor adaptor(operands, attrs, properties, regions);
4852 return UIntType::get(attrs.getContext(), 1,
4853 isConst(adaptor.getInput().getType()));
4856template <
typename OpTy>
4858 auto *context = parser.getContext();
4860 OpAsmParser::UnresolvedOperand input;
4861 std::string fieldName;
4863 if (parser.parseOperand(input) || parser.parseLSquare() ||
4864 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4865 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4866 parser.parseType(inputType))
4869 if (parser.resolveOperand(input, inputType, result.operands))
4872 auto bundleType = type_dyn_cast<typename OpTy::InputType>(inputType);
4874 return parser.emitError(parser.getNameLoc(),
4875 "input must be bundle type, got ")
4877 auto fieldIndex = bundleType.getElementIndex(fieldName);
4879 return parser.emitError(parser.getNameLoc(),
4880 "unknown field " + fieldName +
" in bundle type ")
4883 result.getOrAddProperties<
typename OpTy::Properties>().setFieldIndex(
4884 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4886 auto type = OpTy::inferReturnType(inputType, *fieldIndex, {});
4889 result.addTypes(type);
4894ParseResult SubtagOp::parse(OpAsmParser &parser, OperationState &result) {
4895 auto *context = parser.getContext();
4897 OpAsmParser::UnresolvedOperand input;
4898 std::string fieldName;
4900 if (parser.parseOperand(input) || parser.parseLSquare() ||
4901 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
4902 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
4903 parser.parseType(inputType))
4906 if (parser.resolveOperand(input, inputType, result.operands))
4909 auto enumType = type_dyn_cast<FEnumType>(inputType);
4911 return parser.emitError(parser.getNameLoc(),
4912 "input must be enum type, got ")
4914 auto fieldIndex = enumType.getElementIndex(fieldName);
4916 return parser.emitError(parser.getNameLoc(),
4917 "unknown field " + fieldName +
" in enum type ")
4920 result.getOrAddProperties<Properties>().setFieldIndex(
4921 IntegerAttr::get(IntegerType::get(context, 32), *fieldIndex));
4923 SmallVector<Type> inferredReturnTypes;
4924 if (failed(SubtagOp::inferReturnTypes(
4925 context, result.location, result.operands,
4926 result.attributes.getDictionary(context), result.getRawProperties(),
4927 result.regions, inferredReturnTypes)))
4929 result.addTypes(inferredReturnTypes);
4934ParseResult SubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4935 return parseSubfieldLikeOp<SubfieldOp>(parser, result);
4937ParseResult OpenSubfieldOp::parse(OpAsmParser &parser, OperationState &result) {
4938 return parseSubfieldLikeOp<OpenSubfieldOp>(parser, result);
4941template <
typename OpTy>
4943 printer <<
' ' << op.getInput() <<
'[';
4944 printer.printKeywordOrString(op.getFieldName());
4946 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4947 elidedAttrs.push_back(
"fieldIndex");
4948 printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
4949 printer <<
" : " << op.getInput().getType();
4951void SubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4952 return printSubfieldLikeOp<SubfieldOp>(*
this, printer);
4954void OpenSubfieldOp::print(::mlir::OpAsmPrinter &printer) {
4955 return printSubfieldLikeOp<OpenSubfieldOp>(*
this, printer);
4958void SubtagOp::print(::mlir::OpAsmPrinter &printer) {
4959 printer <<
' ' << getInput() <<
'[';
4962 ::llvm::SmallVector<::llvm::StringRef, 2> elidedAttrs;
4963 elidedAttrs.push_back(
"fieldIndex");
4964 printer.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs);
4965 printer <<
" : " << getInput().getType();
4968template <
typename OpTy>
4970 if (op.getFieldIndex() >=
4971 firrtl::type_cast<typename OpTy::InputType>(op.getInput().getType())
4973 return op.emitOpError(
"subfield element index is greater than the number "
4974 "of fields in the bundle type");
4977LogicalResult SubfieldOp::verify() {
4978 return verifySubfieldLike<SubfieldOp>(*
this);
4980LogicalResult OpenSubfieldOp::verify() {
4981 return verifySubfieldLike<OpenSubfieldOp>(*
this);
4984LogicalResult SubtagOp::verify() {
4985 if (getFieldIndex() >= getInput().getType().base().getNumElements())
4986 return emitOpError(
"subfield element index is greater than the number "
4987 "of fields in the bundle type");
4997 SmallVector<Operation *, 8> worklist({op});
5001 bool constant =
true;
5007 while (constant && !(worklist.empty()))
5008 TypeSwitch<Operation *>(worklist.pop_back_val())
5009 .Case<NodeOp, AsSIntPrimOp, AsUIntPrimOp>([&](
auto op) {
5010 if (
auto definingOp = op.getInput().getDefiningOp())
5011 worklist.push_back(definingOp);
5014 .Case<WireOp, SubindexOp, SubfieldOp>([&](
auto op) {
5015 for (
auto &use : op.getResult().getUses())
5016 worklist.push_back(use.getOwner());
5018 .Case<ConstantOp, SpecialConstantOp, AggregateConstantOp>([](
auto) {})
5019 .Default([&](
auto) { constant =
false; });
5028 if (
auto *op = value.getDefiningOp())
5033LogicalResult ConstCastOp::verify() {
5035 return emitOpError() << getInput().getType()
5036 <<
" is not 'const'-castable to "
5037 << getResult().getType();
5041FIRRTLType SubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5042 std::optional<Location> loc) {
5043 auto inType = type_cast<BundleType>(type);
5045 if (fieldIndex >= inType.getNumElements())
5047 "subfield element index is greater than the "
5048 "number of fields in the bundle type");
5052 return inType.getElementTypePreservingConst(fieldIndex);
5055FIRRTLType OpenSubfieldOp::inferReturnType(Type type, uint32_t fieldIndex,
5056 std::optional<Location> loc) {
5057 auto inType = type_cast<OpenBundleType>(type);
5059 if (fieldIndex >= inType.getNumElements())
5061 "subfield element index is greater than the "
5062 "number of fields in the bundle type");
5066 return inType.getElementTypePreservingConst(fieldIndex);
5069bool SubfieldOp::isFieldFlipped() {
5070 BundleType bundle = getInput().getType();
5071 return bundle.getElement(getFieldIndex()).isFlip;
5073bool OpenSubfieldOp::isFieldFlipped() {
5074 auto bundle = getInput().getType();
5075 return bundle.getElement(getFieldIndex()).isFlip;
5078FIRRTLType SubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5079 std::optional<Location> loc) {
5080 if (
auto vectorType = type_dyn_cast<FVectorType>(type)) {
5081 if (fieldIndex < vectorType.getNumElements())
5082 return vectorType.getElementTypePreservingConst();
5084 "' in vector type ", type);
5089FIRRTLType OpenSubindexOp::inferReturnType(Type type, uint32_t fieldIndex,
5090 std::optional<Location> loc) {
5091 if (
auto vectorType = type_dyn_cast<OpenVectorType>(type)) {
5092 if (fieldIndex < vectorType.getNumElements())
5093 return vectorType.getElementTypePreservingConst();
5095 "' in vector type ", type);
5101FIRRTLType SubtagOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5102 OpaqueProperties properties,
5103 mlir::RegionRange regions,
5104 std::optional<Location> loc) {
5105 Adaptor adaptor(operands, attrs, properties, regions);
5106 auto inType = type_cast<FEnumType>(adaptor.getInput().getType());
5107 auto fieldIndex = adaptor.getFieldIndex();
5109 if (fieldIndex >= inType.getNumElements())
5111 "subtag element index is greater than the "
5112 "number of fields in the enum type");
5116 auto elementType = inType.getElement(fieldIndex).type;
5120FIRRTLType SubaccessOp::inferReturnType(Type inType, Type indexType,
5121 std::optional<Location> loc) {
5122 if (!type_isa<UIntType>(indexType))
5126 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
5128 return vectorType.getElementTypePreservingConst();
5129 return vectorType.getElementType().getAllConstDroppedType();
5137 std::optional<Location> loc) {
5138 auto inType = type_cast<FEnumType>(input);
5139 return UIntType::get(inType.getContext(), inType.getTagWidth());
5142ParseResult MultibitMuxOp::parse(OpAsmParser &parser, OperationState &result) {
5143 OpAsmParser::UnresolvedOperand index;
5144 SmallVector<OpAsmParser::UnresolvedOperand, 16> inputs;
5145 Type indexType, elemType;
5147 if (parser.parseOperand(index) || parser.parseComma() ||
5148 parser.parseOperandList(inputs) ||
5149 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5150 parser.parseType(indexType) || parser.parseComma() ||
5151 parser.parseType(elemType))
5154 if (parser.resolveOperand(index, indexType, result.operands))
5157 result.addTypes(elemType);
5159 return parser.resolveOperands(inputs, elemType, result.operands);
5162void MultibitMuxOp::print(OpAsmPrinter &p) {
5163 p <<
" " << getIndex() <<
", ";
5164 p.printOperands(getInputs());
5165 p.printOptionalAttrDict((*this)->getAttrs());
5166 p <<
" : " << getIndex().getType() <<
", " << getType();
5169FIRRTLType MultibitMuxOp::inferReturnType(ValueRange operands,
5170 DictionaryAttr attrs,
5171 OpaqueProperties properties,
5172 mlir::RegionRange regions,
5173 std::optional<Location> loc) {
5174 if (operands.size() < 2)
5178 if (!llvm::all_of(operands.drop_front(2), [&](
auto op) {
5179 return operands[1].getType() == op.getType();
5183 return type_cast<FIRRTLType>(operands[1].getType());
5190LogicalResult ObjectSubfieldOp::inferReturnTypes(
5191 MLIRContext *context, std::optional<mlir::Location> location,
5192 ValueRange operands, DictionaryAttr attributes, OpaqueProperties properties,
5193 RegionRange regions, llvm::SmallVectorImpl<Type> &inferredReturnTypes) {
5195 inferReturnType(operands, attributes, properties, regions, location);
5198 inferredReturnTypes.push_back(type);
5202Type ObjectSubfieldOp::inferReturnType(Type inType, uint32_t fieldIndex,
5203 std::optional<Location> loc) {
5204 auto classType = dyn_cast<ClassType>(inType);
5208 if (classType.getNumElements() <= fieldIndex)
5210 "number of fields in the object");
5211 return classType.getElement(fieldIndex).type;
5214void ObjectSubfieldOp::print(OpAsmPrinter &p) {
5215 auto input = getInput();
5216 auto classType = input.getType();
5217 p <<
' ' << input <<
"[";
5218 p.printKeywordOrString(classType.getElement(getIndex()).name);
5220 p.printOptionalAttrDict((*this)->getAttrs(), std::array{StringRef(
"index")});
5221 p <<
" : " << classType;
5224ParseResult ObjectSubfieldOp::parse(OpAsmParser &parser,
5225 OperationState &result) {
5226 auto *context = parser.getContext();
5228 OpAsmParser::UnresolvedOperand input;
5229 std::string fieldName;
5230 ClassType inputType;
5231 if (parser.parseOperand(input) || parser.parseLSquare() ||
5232 parser.parseKeywordOrString(&fieldName) || parser.parseRSquare() ||
5233 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
5234 parser.parseType(inputType) ||
5235 parser.resolveOperand(input, inputType, result.operands))
5238 auto index = inputType.getElementIndex(fieldName);
5240 return parser.emitError(parser.getNameLoc(),
5241 "unknown field " + fieldName +
" in class type ")
5243 result.getOrAddProperties<Properties>().setIndex(
5244 IntegerAttr::get(IntegerType::get(context, 32), *index));
5246 SmallVector<Type> inferredReturnTypes;
5247 if (failed(inferReturnTypes(context, result.location, result.operands,
5248 result.attributes.getDictionary(context),
5249 result.getRawProperties(), result.regions,
5250 inferredReturnTypes)))
5252 result.addTypes(inferredReturnTypes);
5269 int32_t &rhsWidth,
bool &isConstResult,
5270 std::optional<Location> loc) {
5272 auto lhsi = type_dyn_cast<IntType>(lhs);
5273 auto rhsi = type_dyn_cast<IntType>(rhs);
5274 if (!lhsi || !rhsi || lhsi.isSigned() != rhsi.isSigned()) {
5277 mlir::emitError(*loc,
"second operand must be an integer type, not ")
5279 else if (!lhsi && rhsi)
5280 mlir::emitError(*loc,
"first operand must be an integer type, not ")
5282 else if (!lhsi && !rhsi)
5283 mlir::emitError(*loc,
"operands must be integer types, not ")
5284 << lhs <<
" and " << rhs;
5286 mlir::emitError(*loc,
"operand signedness must match");
5291 lhsWidth = lhsi.getWidthOrSentinel();
5292 rhsWidth = rhsi.getWidthOrSentinel();
5293 isConstResult = lhsi.isConst() && rhsi.isConst();
5298 assert(op->getNumOperands() == 2 &&
5299 "SameOperandsIntTypeKind on non-binary op");
5300 int32_t lhsWidth, rhsWidth;
5303 op->getOperand(1).getType(), lhsWidth,
5304 rhsWidth, isConstResult, op->getLoc()));
5308 std::optional<Location> loc) {
5309 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5310 bool isConstResult =
false;
5314 if (lhsWidth != -1 && rhsWidth != -1)
5315 resultWidth = std::max(lhsWidth, rhsWidth) + 1;
5316 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5321 std::optional<Location> loc) {
5322 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5323 bool isConstResult =
false;
5327 if (lhsWidth != -1 && rhsWidth != -1)
5328 resultWidth = lhsWidth + rhsWidth;
5330 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5335 std::optional<Location> loc) {
5336 int32_t lhsWidth, rhsWidth;
5337 bool isConstResult =
false;
5342 if (type_isa<UIntType>(lhs))
5343 return UIntType::get(lhs.getContext(), lhsWidth, isConstResult);
5346 int32_t resultWidth = lhsWidth != -1 ? lhsWidth + 1 : -1;
5347 return SIntType::get(lhs.getContext(), resultWidth, isConstResult);
5351 std::optional<Location> loc) {
5352 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5353 bool isConstResult =
false;
5357 if (lhsWidth != -1 && rhsWidth != -1)
5358 resultWidth = std::min(lhsWidth, rhsWidth);
5359 return IntType::get(lhs.getContext(), type_isa<SIntType>(lhs), resultWidth,
5364 std::optional<Location> loc) {
5365 int32_t lhsWidth, rhsWidth, resultWidth = -1;
5366 bool isConstResult =
false;
5370 if (lhsWidth != -1 && rhsWidth != -1) {
5371 resultWidth = std::max(lhsWidth, rhsWidth);
5372 if (lhsWidth == resultWidth && lhs.
isConst() == isConstResult &&
5375 if (rhsWidth == resultWidth && rhs.
isConst() == isConstResult &&
5379 return UIntType::get(lhs.getContext(), resultWidth, isConstResult);
5383 std::optional<Location> loc) {
5384 if (!type_isa<FVectorType>(lhs) || !type_isa<FVectorType>(rhs))
5387 auto lhsVec = type_cast<FVectorType>(lhs);
5388 auto rhsVec = type_cast<FVectorType>(rhs);
5390 if (lhsVec.getNumElements() != rhsVec.getNumElements())
5395 rhsVec.getElementTypePreservingConst(), loc);
5398 auto elemBaseType = type_cast<FIRRTLBaseType>(elemType);
5399 return FVectorType::get(elemBaseType, lhsVec.getNumElements(),
5400 lhsVec.isConst() && rhsVec.isConst() &&
5401 elemBaseType.isConst());
5405 std::optional<Location> loc) {
5406 return UIntType::get(lhs.getContext(), 1,
isConst(lhs) &&
isConst(rhs));
5409FIRRTLType CatPrimOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
5410 OpaqueProperties properties,
5411 mlir::RegionRange regions,
5412 std::optional<Location> loc) {
5414 if (operands.empty())
5415 return UIntType::get(attrs.getContext(), 0);
5418 bool isSigned = type_isa<SIntType>(operands[0].getType());
5419 for (
auto operand : operands) {
5420 auto type = type_dyn_cast<IntType>(operand.getType());
5423 if (type.isSigned() != isSigned)
5425 "all operands must have same signedness");
5429 int32_t resultWidth = 0;
5430 bool isConstResult =
true;
5432 for (
auto operand : operands) {
5433 auto type = type_cast<IntType>(operand.getType());
5434 int32_t width = type.getWidthOrSentinel();
5441 if (resultWidth != -1)
5442 resultWidth += width;
5445 isConstResult &= type.isConst();
5449 return UIntType::get(attrs.getContext(), resultWidth, isConstResult);
5453 std::optional<Location> loc) {
5454 auto lhsi = type_dyn_cast<IntType>(lhs);
5455 auto rhsui = type_dyn_cast<UIntType>(rhs);
5456 if (!rhsui || !lhsi)
5458 loc,
"first operand should be integer, second unsigned int");
5462 auto width = lhsi.getWidthOrSentinel();
5463 if (width == -1 || !rhsui.getWidth().has_value()) {
5466 auto amount = *rhsui.getWidth();
5469 "shift amount too large: second operand of "
5470 "dshl is wider than 31 bits");
5471 int64_t newWidth = (int64_t)width + ((int64_t)1 << amount) - 1;
5472 if (newWidth > INT32_MAX)
5474 loc,
"shift amount too large: first operand shifted by maximum "
5475 "amount exceeds maximum width");
5478 return IntType::get(lhs.getContext(), lhsi.isSigned(), width,
5479 lhsi.
isConst() && rhsui.isConst());
5483 std::optional<Location> loc) {
5484 auto lhsi = type_dyn_cast<IntType>(lhs);
5485 auto rhsu = type_dyn_cast<UIntType>(rhs);
5488 loc,
"first operand should be integer, second unsigned int");
5489 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5493 std::optional<Location> loc) {
5494 auto lhsi = type_dyn_cast<IntType>(lhs);
5495 auto rhsu = type_dyn_cast<UIntType>(rhs);
5498 loc,
"first operand should be integer, second unsigned int");
5499 return lhsi.getConstType(lhsi.isConst() && rhsu.isConst());
5507 std::optional<Location> loc) {
5508 return UIntType::get(input.getContext(), 32);
5512 std::optional<Location> loc) {
5513 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5516 int32_t width = base.getBitWidthOrSentinel();
5519 return SIntType::get(input.getContext(), width, base.
isConst());
5523 std::optional<Location> loc) {
5524 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5527 int32_t width = base.getBitWidthOrSentinel();
5530 return UIntType::get(input.getContext(), width, base.
isConst());
5534 std::optional<Location> loc) {
5535 auto base = type_dyn_cast<FIRRTLBaseType>(input);
5538 "operand must be single bit scalar base type");
5539 int32_t width = base.getBitWidthOrSentinel();
5540 if (width == -2 || width == 0 || width > 1)
5542 return AsyncResetType::get(input.getContext(), base.
isConst());
5546 std::optional<Location> loc) {
5547 return ClockType::get(input.getContext(),
isConst(input));
5551 std::optional<Location> loc) {
5552 if (
auto uiType = type_dyn_cast<UIntType>(input)) {
5553 auto width = uiType.getWidthOrSentinel();
5556 return SIntType::get(input.getContext(), width, uiType.
isConst());
5559 if (type_isa<SIntType>(input))
5566 std::optional<Location> loc) {
5567 auto inputi = type_dyn_cast<IntType>(input);
5570 int32_t width = inputi.getWidthOrSentinel();
5573 return SIntType::get(input.getContext(), width, inputi.
isConst());
5577 std::optional<Location> loc) {
5578 auto inputi = type_dyn_cast<IntType>(input);
5581 if (isa<UIntType>(inputi))
5583 return UIntType::get(input.getContext(), inputi.getWidthOrSentinel(),
5588 std::optional<Location> loc) {
5589 return UIntType::get(input.getContext(), 1,
isConst(input));
5598 std::optional<Location> loc) {
5599 auto inputi = type_dyn_cast<IntType>(input);
5602 loc,
"input type should be the int type but got ", input);
5607 loc,
"high must be equal or greater than low, but got high = ", high,
5615 int32_t width = inputi.getWidthOrSentinel();
5616 if (width != -1 && high >= width)
5619 "high must be smaller than the width of input, but got high = ", high,
5620 ", width = ", width);
5622 return UIntType::get(input.getContext(), high - low + 1, inputi.
isConst());
5626 std::optional<Location> loc) {
5628 auto inputi = type_dyn_cast<IntType>(input);
5629 if (amount < 0 || !inputi)
5631 loc,
"operand must have integer type and amount must be >= 0");
5633 int32_t width = inputi.getWidthOrSentinel();
5634 if (width != -1 && amount > width)
5637 return UIntType::get(input.getContext(), amount, inputi.
isConst());
5652 bool isConstCondition,
5653 std::optional<Location> loc) {
5659 if (high.getTypeID() != low.getTypeID())
5660 return emitInferRetTypeError<FIRRTLBaseType>(
5661 loc,
"incompatible mux operand types, true value type: ", high,
5662 ", false value type: ", low);
5664 bool outerTypeIsConst = isConstCondition && low.
isConst() && high.
isConst();
5669 if (type_isa<IntType>(low)) {
5674 if (highWidth == -1)
5676 return (lowWidth > highWidth ? low : high).getConstType(outerTypeIsConst);
5681 auto highEnum = type_dyn_cast<FEnumType>(high);
5682 auto lowEnum = type_dyn_cast<FEnumType>(low);
5683 if (lowEnum && highEnum) {
5684 if (lowEnum.getNumElements() != highEnum.getNumElements())
5685 return emitInferRetTypeError<FIRRTLBaseType>(
5686 loc,
"incompatible mux operand types, true value type: ", high,
5687 ", false value type: ", low);
5688 SmallVector<FEnumType::EnumElement> elements;
5689 for (
auto [high, low] : llvm::zip_equal(highEnum, lowEnum)) {
5691 if (high.name != low.name || high.value != low.value)
5692 return emitInferRetTypeError<FIRRTLBaseType>(
5693 loc,
"incompatible mux operand types, true value type: ", highEnum,
5694 ", false value type: ", lowEnum);
5701 elements.emplace_back(high.name, high.value, inner);
5703 return FEnumType::get(high.getContext(), elements, outerTypeIsConst);
5707 auto highVector = type_dyn_cast<FVectorType>(high);
5708 auto lowVector = type_dyn_cast<FVectorType>(low);
5709 if (highVector && lowVector &&
5710 highVector.getNumElements() == lowVector.getNumElements()) {
5712 lowVector.getElementTypePreservingConst(),
5713 isConstCondition, loc);
5716 return FVectorType::get(inner, lowVector.getNumElements(),
5721 auto highBundle = type_dyn_cast<BundleType>(high);
5722 auto lowBundle = type_dyn_cast<BundleType>(low);
5723 if (highBundle && lowBundle) {
5724 auto highElements = highBundle.getElements();
5725 auto lowElements = lowBundle.getElements();
5728 SmallVector<BundleType::BundleElement> newElements;
5730 bool failed =
false;
5732 if (highElements[i].name != lowElements[i].name ||
5733 highElements[i].isFlip != lowElements[i].isFlip) {
5737 auto element = highElements[i];
5739 highBundle.getElementTypePreservingConst(i),
5740 lowBundle.getElementTypePreservingConst(i), isConstCondition, loc);
5743 newElements.push_back(element);
5746 return BundleType::get(low.getContext(), newElements, outerTypeIsConst);
5748 return emitInferRetTypeError<FIRRTLBaseType>(
5749 loc,
"incompatible mux operand bundle fields, true value type: ", high,
5750 ", false value type: ", low);
5755 return emitInferRetTypeError<FIRRTLBaseType>(
5756 loc,
"invalid mux operand types, true value type: ", high,
5757 ", false value type: ", low);
5762 std::optional<Location> loc) {
5763 auto highType = type_dyn_cast<FIRRTLBaseType>(high);
5764 auto lowType = type_dyn_cast<FIRRTLBaseType>(low);
5765 if (!highType || !lowType)
5770FIRRTLType Mux2CellIntrinsicOp::inferReturnType(ValueRange operands,
5771 DictionaryAttr attrs,
5772 OpaqueProperties properties,
5773 mlir::RegionRange regions,
5774 std::optional<Location> loc) {
5775 auto highType = type_dyn_cast<FIRRTLBaseType>(operands[1].getType());
5776 auto lowType = type_dyn_cast<FIRRTLBaseType>(operands[2].getType());
5777 if (!highType || !lowType)
5783FIRRTLType Mux4CellIntrinsicOp::inferReturnType(ValueRange operands,
5784 DictionaryAttr attrs,
5785 OpaqueProperties properties,
5786 mlir::RegionRange regions,
5787 std::optional<Location> loc) {
5788 SmallVector<FIRRTLBaseType> types;
5790 for (
unsigned i = 1; i < 5; i++) {
5791 types.push_back(type_dyn_cast<FIRRTLBaseType>(operands[i].getType()));
5796 isConst(operands[0].getType()), loc);
5800 result = types.back();
5807 std::optional<Location> loc) {
5808 auto inputi = type_dyn_cast<IntType>(input);
5809 if (amount < 0 || !inputi)
5811 loc,
"pad input must be integer and amount must be >= 0");
5813 int32_t width = inputi.getWidthOrSentinel();
5817 width = std::max<int32_t>(width, amount);
5818 return IntType::get(input.getContext(), inputi.isSigned(), width,
5823 std::optional<Location> loc) {
5824 auto inputi = type_dyn_cast<IntType>(input);
5825 if (amount < 0 || !inputi)
5827 loc,
"shl input must be integer and amount must be >= 0");
5829 int32_t width = inputi.getWidthOrSentinel();
5833 return IntType::get(input.getContext(), inputi.isSigned(), width,
5838 std::optional<Location> loc) {
5839 auto inputi = type_dyn_cast<IntType>(input);
5840 if (amount < 0 || !inputi)
5842 loc,
"shr input must be integer and amount must be >= 0");
5844 int32_t width = inputi.getWidthOrSentinel();
5847 int32_t minWidth = inputi.isUnsigned() ? 0 : 1;
5848 width = std::max<int32_t>(minWidth, width - amount);
5851 return IntType::get(input.getContext(), inputi.isSigned(), width,
5856 std::optional<Location> loc) {
5858 auto inputi = type_dyn_cast<IntType>(input);
5859 if (amount < 0 || !inputi)
5861 loc,
"tail input must be integer and amount must be >= 0");
5863 int32_t width = inputi.getWidthOrSentinel();
5867 loc,
"amount must be less than or equal operand width");
5878void VerbatimExprOp::getAsmResultNames(
5879 function_ref<
void(Value, StringRef)> setNameFn) {
5883 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5884 auto name = getText();
5886 if (name.starts_with(
"`"))
5887 name = name.drop_front();
5888 name = name.take_while(isOkCharacter);
5890 setNameFn(getResult(), name);
5897void VerbatimWireOp::getAsmResultNames(
5898 function_ref<
void(Value, StringRef)> setNameFn) {
5902 auto isOkCharacter = [](
char c) {
return llvm::isAlnum(c) || c ==
'_'; };
5903 auto name = getText();
5905 if (name.starts_with(
"`"))
5906 name = name.drop_front();
5907 name = name.take_while(isOkCharacter);
5909 setNameFn(getResult(), name);
5920 op->emitError() <<
"unknown width is not allowed for DPI";
5921 return WalkResult::interrupt();
5923 if (width == 1 || width == 8 || width == 16 || width == 32 ||
5925 return WalkResult::advance();
5927 <<
"integer types used by DPI functions must have a "
5928 "specific bit width; "
5929 "it must be equal to 1(bit), 8(byte), 16(shortint), "
5930 "32(int), 64(longint) "
5931 "or greater than 64, but got "
5933 return WalkResult::interrupt();
5938LogicalResult DPICallIntrinsicOp::verify() {
5939 if (
auto inputNames = getInputNames()) {
5940 if (getInputs().size() != inputNames->size())
5941 return emitError() <<
"inputNames has " << inputNames->size()
5942 <<
" elements but there are " << getInputs().size()
5943 <<
" input arguments";
5945 if (
auto outputName = getOutputName())
5946 if (getNumResults() == 0)
5947 return emitError() <<
"output name is given but there is no result";
5949 auto checkType = [
this](Type type) {
5952 return success(llvm::all_of(this->getResultTypes(), checkType) &&
5953 llvm::all_of(this->getOperandTypes(), checkType));
5956SmallVector<std::pair<circt::FieldRef, circt::FieldRef>>
5957DPICallIntrinsicOp::computeDataFlow() {
5961 SmallVector<std::pair<circt::FieldRef, circt::FieldRef>> deps;
5963 for (
auto operand : getOperands()) {
5964 auto type = type_cast<FIRRTLBaseType>(operand.getType());
5966 SmallVector<circt::FieldRef> operandFields;
5969 operandFields.push_back(baseFieldRef.getSubField(dstIndex));
5973 for (
auto result : getResults())
5976 for (
auto field : operandFields)
5977 deps.emplace_back(
circt::
FieldRef(result, dstIndex), field);
5987LogicalResult HWStructCastOp::verify() {
5989 BundleType bundleType;
5990 hw::StructType structType;
5991 if ((bundleType = type_dyn_cast<BundleType>(getOperand().getType()))) {
5992 structType = dyn_cast<hw::StructType>(getType());
5994 return emitError(
"result type must be a struct");
5995 }
else if ((bundleType = type_dyn_cast<BundleType>(getType()))) {
5996 structType = dyn_cast<hw::StructType>(getOperand().getType());
5998 return emitError(
"operand type must be a struct");
6000 return emitError(
"either source or result type must be a bundle type");
6003 auto firFields = bundleType.getElements();
6004 auto hwFields = structType.getElements();
6005 if (firFields.size() != hwFields.size())
6006 return emitError(
"bundle and struct have different number of fields");
6008 for (
size_t findex = 0, fend = firFields.size(); findex < fend; ++findex) {
6009 if (firFields[findex].name.getValue() != hwFields[findex].name)
6010 return emitError(
"field names don't match '")
6011 << firFields[findex].name.getValue() <<
"', '"
6012 << hwFields[findex].name.getValue() <<
"'";
6016 if (firWidth > 0 && hwWidth > 0 && firWidth != hwWidth)
6017 return emitError(
"size of field '")
6018 << hwFields[findex].name.getValue() <<
"' don't match " << firWidth
6025LogicalResult BitCastOp::verify() {
6026 auto inTypeBits =
getBitWidth(getInput().getType(),
true);
6028 if (inTypeBits.has_value() && resTypeBits.has_value()) {
6030 if (*inTypeBits == *resTypeBits) {
6033 return emitError(
"cannot cast non-'const' input type ")
6034 << getOperand().getType() <<
" to 'const' result type "
6038 return emitError(
"the bitwidth of input (")
6039 << *inTypeBits <<
") and result (" << *resTypeBits
6042 if (!inTypeBits.has_value())
6043 return emitError(
"bitwidth cannot be determined for input operand type ")
6044 << getInput().getType();
6045 return emitError(
"bitwidth cannot be determined for result type ")
6056 NamedAttrList &resultAttrs) {
6057 auto result = parser.parseOptionalAttrDict(resultAttrs);
6058 if (!resultAttrs.get(
"annotations"))
6059 resultAttrs.append(
"annotations", parser.getBuilder().getArrayAttr({}));
6065 DictionaryAttr attr,
6066 ArrayRef<StringRef> extraElides = {}) {
6067 SmallVector<StringRef> elidedAttrs(extraElides.begin(), extraElides.end());
6069 if (op->getAttrOfType<ArrayAttr>(
"annotations").empty())
6070 elidedAttrs.push_back(
"annotations");
6072 elidedAttrs.push_back(
"nameKind");
6074 p.printOptionalAttrDict(op->getAttrs(), elidedAttrs);
6080 NamedAttrList &resultAttrs) {
6083 if (!resultAttrs.get(
"portAnnotations")) {
6084 SmallVector<Attribute, 16> portAnnotations(
6085 parser.getNumResults(), parser.getBuilder().getArrayAttr({}));
6086 resultAttrs.append(
"portAnnotations",
6087 parser.getBuilder().getArrayAttr(portAnnotations));
6094 DictionaryAttr attr,
6095 ArrayRef<StringRef> extraElides = {}) {
6096 SmallVector<StringRef, 2> elidedAttrs(extraElides.begin(), extraElides.end());
6098 if (llvm::all_of(op->getAttrOfType<ArrayAttr>(
"portAnnotations"),
6099 [&](Attribute a) { return cast<ArrayAttr>(a).empty(); }))
6100 elidedAttrs.push_back(
"portAnnotations");
6109 firrtl::NameKindEnumAttr &result) {
6112 if (!parser.parseOptionalKeyword(&keyword,
6113 {
"interesting_name",
"droppable_name"})) {
6114 auto kind = symbolizeNameKindEnum(keyword);
6115 result = NameKindEnumAttr::get(parser.getContext(), kind.value());
6121 NameKindEnumAttr::get(parser.getContext(), NameKindEnum::DroppableName);
6126 firrtl::NameKindEnumAttr attr,
6127 ArrayRef<StringRef> extraElides = {}) {
6128 if (attr.getValue() != NameKindEnum::DroppableName)
6129 p <<
" " << stringifyNameKindEnum(attr.getValue());
6137 NamedAttrList &resultAttrs) {
6145 DictionaryAttr attrs) {
6146 SmallVector<StringRef, 4> elides;
6148 elides.push_back(Forceable::getForceableAttrName());
6157static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
6157static ParseResult
parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs) {
…}
6162static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
6162static void printMemOp(OpAsmPrinter &p, Operation *op, DictionaryAttr attr) {
…}
6173 if (ClassType::parseInterface(parser, type))
6180 type.printInterface(p);
6188 NamedAttrList &resultAttrs) {
6189 auto result = p.parseOptionalAttrDict(resultAttrs);
6190 if (!resultAttrs.get(
"name"))
6191 resultAttrs.append(
"name", p.getBuilder().getStringAttr(
""));
6197 DictionaryAttr attr,
6198 ArrayRef<StringRef> extraElides = {}) {
6199 SmallVector<StringRef> elides(extraElides.begin(), extraElides.end());
6200 if (op->getAttrOfType<StringAttr>(
"name").getValue().empty())
6201 elides.push_back(
"name");
6203 p.printOptionalAttrDict(op->getAttrs(), elides);
6207 NamedAttrList &resultAttrs) {
6212 DictionaryAttr attr) {
6217 NamedAttrList &resultAttrs) {
6222 DictionaryAttr attr) {
6224 {
"formatString",
"outputFile",
"operandSegmentSizes"});
6232 DictionaryAttr attr) {
6241 DictionaryAttr attr) {
6250 OpAsmSetValueNameFn setNameFn) {
6253 if (op->getNumResults() == 1)
6254 if (
auto nameAttr = op->getAttrOfType<StringAttr>(
"name"))
6255 setNameFn(op->getResult(0), nameAttr.getValue());
6258void AddPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6262void AndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6266void AndRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6270void SizeOfIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6273void AsAsyncResetPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6276void AsClockPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6279void AsSIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6282void AsUIntPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6285void BitsPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6288void CatPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6291void CvtPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6294void DShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6297void DShlwPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6300void DShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6303void DivPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6306void EQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6309void GEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6312void GTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6315void GenericIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6318void HeadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6321void IntegerAddOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6324void IntegerMulOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6327void IntegerShrOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6330void IntegerShlOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6333void IsTagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6336void IsXIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6339void PlusArgsValueIntrinsicOp::getAsmResultNames(
6340 OpAsmSetValueNameFn setNameFn) {
6343void PlusArgsTestIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6346void LEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6349void LTPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6352void MulPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6355void MultibitMuxOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6358void MuxPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6361void Mux4CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6364void Mux2CellIntrinsicOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6367void NEQPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6370void NegPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6373void NotPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6376void OrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6379void OrRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6382void PadPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6385void RemPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6388void ShlPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6391void ShrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6395void SubPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6399void SubaccessOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6403void SubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6407void OpenSubfieldOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6411void SubtagOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6415void SubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6419void OpenSubindexOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6423void TagExtractOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6427void TailPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6431void XorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6435void XorRPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6439void UninferredResetCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6443void ConstCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6447void ElementwiseXorPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6451void ElementwiseOrPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6455void ElementwiseAndPrimOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6463void RefCastOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6467void RefResolveOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6471void RefSendOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6475void RefSubOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6479void RWProbeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6483FIRRTLType RefResolveOp::inferReturnType(ValueRange operands,
6484 DictionaryAttr attrs,
6485 OpaqueProperties properties,
6486 mlir::RegionRange regions,
6487 std::optional<Location> loc) {
6488 Type inType = operands[0].getType();
6489 auto inRefType = type_dyn_cast<RefType>(inType);
6492 loc,
"ref.resolve operand must be ref type, not ", inType);
6493 return inRefType.getType();
6496FIRRTLType RefSendOp::inferReturnType(ValueRange operands, DictionaryAttr attrs,
6497 OpaqueProperties properties,
6498 mlir::RegionRange regions,
6499 std::optional<Location> loc) {
6500 Type inType = operands[0].getType();
6501 auto inBaseType = type_dyn_cast<FIRRTLBaseType>(inType);
6504 loc,
"ref.send operand must be base type, not ", inType);
6505 return RefType::get(inBaseType.getPassiveType());
6508FIRRTLType RefSubOp::inferReturnType(Type type, uint32_t fieldIndex,
6509 std::optional<Location> loc) {
6510 auto refType = type_dyn_cast<RefType>(type);
6513 auto inType = refType.getType();
6519 if (
auto vectorType = type_dyn_cast<FVectorType>(inType)) {
6520 if (fieldIndex < vectorType.getNumElements())
6521 return RefType::get(
6522 vectorType.getElementType().getConstType(
6523 vectorType.isConst() || vectorType.getElementType().isConst()),
6524 refType.getForceable(), refType.getLayer());
6526 "' in RefType of vector type ", refType);
6528 if (
auto bundleType = type_dyn_cast<BundleType>(inType)) {
6529 if (fieldIndex >= bundleType.getNumElements()) {
6531 "subfield element index is greater than "
6532 "the number of fields in the bundle type");
6534 return RefType::get(
6535 bundleType.getElement(fieldIndex)
6537 bundleType.isConst() ||
6538 bundleType.getElement(fieldIndex).type.isConst()),
6539 refType.getForceable(), refType.getLayer());
6543 loc,
"ref.sub op requires a RefType of vector or bundle base type");
6546LogicalResult RefCastOp::verify() {
6550 getOperation(), srcLayers, dstLayers,
6551 "cannot discard layer requirements of input reference",
6552 "discarding layer requirements");
6555LogicalResult RefResolveOp::verify() {
6559 getOperation(), srcLayers, dstLayers,
6560 "ambient layers are insufficient to resolve reference");
6564 auto targetRef = getTarget();
6565 if (targetRef.getModule() !=
6566 (*this)->getParentOfType<FModuleLike>().getModuleNameAttr())
6567 return emitOpError() <<
"has non-local target";
6569 auto target = ns.
lookup(targetRef);
6571 return emitOpError() <<
"has target that cannot be resolved: " << targetRef;
6573 auto checkFinalType = [&](
auto type, Location loc) -> LogicalResult {
6578 auto baseType = type_dyn_cast<FIRRTLBaseType>(fType);
6579 if (!baseType || baseType.getPassiveType() != getType().getType()) {
6580 auto diag = emitOpError(
"has type mismatch: target resolves to ")
6581 << fType <<
" instead of expected " << getType().getType();
6582 diag.attachNote(loc) <<
"target resolves here";
6587 if (target.isPort()) {
6588 auto mod = cast<FModuleLike>(target.getOp());
6589 return checkFinalType(mod.getPortType(target.getPort()),
6590 mod.getPortLocation(target.getPort()));
6592 hw::InnerSymbolOpInterface symOp =
6593 cast<hw::InnerSymbolOpInterface>(target.getOp());
6594 if (!symOp.getTargetResult())
6595 return emitOpError(
"has target that cannot be probed")
6596 .attachNote(symOp.getLoc())
6597 .append(
"target resolves here");
6599 symOp.getTargetResult().getParentBlock()->findAncestorOpInBlock(**
this);
6600 if (!ancestor || !symOp->isBeforeInBlock(ancestor))
6601 return emitOpError(
"is not dominated by target")
6602 .attachNote(symOp.getLoc())
6603 .append(
"target here");
6604 return checkFinalType(symOp.getTargetResult().getType(), symOp.getLoc());
6607LogicalResult RefForceOp::verify() {
6611 getOperation(), destLayers, ambientLayers,
6612 "has insufficient ambient layers to force its reference");
6615LogicalResult RefForceInitialOp::verify() {
6619 getOperation(), destLayers, ambientLayers,
6620 "has insufficient ambient layers to force its reference");
6623LogicalResult RefReleaseOp::verify() {
6627 getOperation(), destLayers, ambientLayers,
6628 "has insufficient ambient layers to release its reference");
6631LogicalResult RefReleaseInitialOp::verify() {
6635 getOperation(), destLayers, ambientLayers,
6636 "has insufficient ambient layers to release its reference");
6639LogicalResult XMRRefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6640 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6642 return emitOpError(
"has an invalid symbol reference");
6644 if (!isa<hw::HierPathOp>(target))
6645 return emitOpError(
"does not target a hierpath op");
6651LogicalResult XMRDerefOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6652 auto *target = symbolTable.lookupNearestSymbolFrom(*
this, getRefAttr());
6654 return emitOpError(
"has an invalid symbol reference");
6656 if (!isa<hw::HierPathOp>(target))
6657 return emitOpError(
"does not target a hierpath op");
6667LogicalResult LayerBlockOp::verify() {
6668 auto layerName = getLayerName();
6669 auto *parentOp = (*this)->getParentOp();
6672 while (isa<WhenOp, MatchOp>(parentOp))
6673 parentOp = parentOp->getParentOp();
6677 auto nestedReferences = layerName.getNestedReferences();
6678 if (nestedReferences.empty()) {
6679 if (!isa<FModuleOp>(parentOp)) {
6680 auto diag = emitOpError() <<
"has an un-nested layer symbol, but does "
6681 "not have a 'firrtl.module' op as a parent";
6682 return diag.attachNote(parentOp->getLoc())
6683 <<
"illegal parent op defined here";
6686 auto parentLayerBlock = dyn_cast<LayerBlockOp>(parentOp);
6687 if (!parentLayerBlock) {
6688 auto diag = emitOpError()
6689 <<
"has a nested layer symbol, but does not have a '"
6690 << getOperationName() <<
"' op as a parent'";
6691 return diag.attachNote(parentOp->getLoc())
6692 <<
"illegal parent op defined here";
6694 auto parentLayerBlockName = parentLayerBlock.getLayerName();
6695 if (parentLayerBlockName.getRootReference() !=
6696 layerName.getRootReference() ||
6697 parentLayerBlockName.getNestedReferences() !=
6698 layerName.getNestedReferences().drop_back()) {
6699 auto diag = emitOpError() <<
"is nested under an illegal layer block";
6700 return diag.attachNote(parentLayerBlock->getLoc())
6701 <<
"illegal parent layer block defined here";
6707 auto result = getBody(0)->walk<mlir::WalkOrder::PreOrder>(
6708 [&](Operation *op) -> WalkResult {
6710 if (isa<LayerBlockOp>(op))
6711 return WalkResult::skip();
6715 for (
auto operand : op->getOperands()) {
6717 if (
auto *definingOp = operand.getDefiningOp())
6721 auto type = operand.getType();
6724 if (isa<PropertyType>(type)) {
6725 auto diag = emitOpError() <<
"captures a property operand";
6726 diag.attachNote(operand.getLoc()) <<
"operand is defined here";
6727 diag.attachNote(op->getLoc()) <<
"operand is used here";
6728 return WalkResult::interrupt();
6733 if (
auto connect = dyn_cast<FConnectLike>(op)) {
6735 if (isa<RefDefineOp>(connect))
6736 return WalkResult::advance();
6743 bool passive =
true;
6745 type_dyn_cast<FIRRTLBaseType>(
connect.getDest().getType()))
6746 passive = type.isPassive();
6755 return WalkResult::advance();
6758 return WalkResult::advance();
6762 <<
"connects to a destination which is defined outside its "
6763 "enclosing layer block";
6764 diag.attachNote(
getLoc()) <<
"enclosing layer block is defined here";
6765 diag.attachNote(dest.getLoc()) <<
"destination is defined here";
6766 return WalkResult::interrupt();
6769 return WalkResult::advance();
6772 return failure(result.wasInterrupted());
6776LayerBlockOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
6778 symbolTable.lookupNearestSymbolFrom<LayerOp>(*
this, getLayerNameAttr());
6780 return emitOpError(
"invalid symbol reference");
6790void TimeOp::getAsmResultNames(OpAsmSetValueNameFn setNameFn) {
6791 setNameFn(getResult(),
"time");
6794void HierarchicalModuleNameOp::getAsmResultNames(
6795 OpAsmSetValueNameFn setNameFn) {
6796 setNameFn(getResult(),
"hierarchicalmodulename");
6799ParseResult FPrintFOp::parse(::mlir::OpAsmParser &parser,
6800 ::mlir::OperationState &result) {
6802 OpAsmParser::UnresolvedOperand clock, cond;
6803 if (parser.parseOperand(clock) || parser.parseComma() ||
6804 parser.parseOperand(cond) || parser.parseComma())
6807 auto parseFormatString =
6808 [&parser](llvm::SMLoc &loc, StringAttr &result,
6809 SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands)
6811 loc = parser.getCurrentLocation();
6814 std::string resultStr;
6815 if (parser.parseString(&resultStr))
6817 result = parser.getBuilder().getStringAttr(resultStr);
6820 if (parser.parseOperandList(operands, AsmParser::Delimiter::OptionalParen))
6826 SmallVector<OpAsmParser::UnresolvedOperand> outputFileSubstitutions,
6828 llvm::SMLoc outputFileLoc, formatStringLoc;
6830 if (parseFormatString(
6832 result.getOrAddProperties<FPrintFOp::Properties>().outputFile,
6833 outputFileSubstitutions) ||
6834 parser.parseComma() ||
6837 result.getOrAddProperties<FPrintFOp::Properties>().formatString,
6845 Type clockType, condType;
6846 SmallVector<Type> restTypes;
6848 if (parser.parseColon() || parser.parseType(clockType) ||
6849 parser.parseComma() || parser.parseType(condType))
6852 if (succeeded(parser.parseOptionalComma())) {
6853 if (parser.parseTypeList(restTypes))
6858 result.getOrAddProperties<FPrintFOp::Properties>().operandSegmentSizes = {
6859 1, 1,
static_cast<int32_t
>(outputFileSubstitutions.size()),
6860 static_cast<int32_t
>(substitutions.size())};
6863 if (parser.resolveOperand(clock, clockType, result.operands) ||
6864 parser.resolveOperand(cond, condType, result.operands) ||
6865 parser.resolveOperands(
6866 outputFileSubstitutions,
6867 ArrayRef(restTypes).take_front(outputFileSubstitutions.size()),
6868 outputFileLoc, result.operands) ||
6869 parser.resolveOperands(
6871 ArrayRef(restTypes).drop_front(outputFileSubstitutions.size()),
6872 formatStringLoc, result.operands))
6878void FPrintFOp::print(OpAsmPrinter &p) {
6879 p <<
" " << getClock() <<
", " << getCond() <<
", ";
6880 p.printAttributeWithoutType(getOutputFileAttr());
6881 if (!getOutputFileSubstitutions().
empty()) {
6883 p.printOperands(getOutputFileSubstitutions());
6887 p.printAttributeWithoutType(getFormatStringAttr());
6888 if (!getSubstitutions().
empty()) {
6890 p.printOperands(getSubstitutions());
6894 p <<
" : " << getClock().getType() <<
", " << getCond().getType();
6895 if (!getOutputFileSubstitutions().
empty() || !getSubstitutions().
empty()) {
6896 for (
auto type : getOperands().drop_front(2).getTypes()) {
6907LogicalResult FFlushOp::verify() {
6908 if (!getOutputFileAttr() && !getOutputFileSubstitutions().
empty())
6909 return emitOpError(
"substitutions without output file are not allowed");
6918 auto ref = getInstanceAttr();
6919 auto target = ns.
lookup(ref);
6921 return emitError() <<
"target " << ref <<
" cannot be resolved";
6923 if (!target.isOpOnly())
6924 return emitError() <<
"target " << ref <<
" is not an operation";
6926 auto instance = dyn_cast<InstanceOp>(target.getOp());
6928 return emitError() <<
"target " << ref <<
" is not an instance";
6930 if (!instance.getDoNotPrint())
6931 return emitError() <<
"target " << ref <<
" is not marked doNotPrint";
6941#define GET_OP_CLASSES
6942#include "circt/Dialect/FIRRTL/FIRRTL.cpp.inc"
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 LogicalResult verifyProbeType(RefType refType, Location loc, CircuitOp circuitOp, SymbolTableCollection &symbolTable, Twine start)
static ArrayAttr fixDomainInfoDeletions(MLIRContext *context, ArrayAttr domainInfoAttr, const llvm::BitVector &portIndices, bool supportsEmptyAttr)
static SmallVector< PortInfo > getPortImpl(FModuleLike module)
static void buildClass(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static void printStopAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static void buildModule(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports, ArrayAttr annotations, ArrayAttr layers)
static LayerSet getLayersFor(Value value)
Get the effective layer requirements for the given value.
static SmallVector< hw::PortInfo > getPortListImpl(FModuleLike module)
ParseResult parseSubfieldLikeOp(OpAsmParser &parser, OperationState &result)
static bool isSameIntTypeKind(Type lhs, Type rhs, int32_t &lhsWidth, int32_t &rhsWidth, bool &isConstResult, std::optional< Location > loc)
If LHS and RHS are both UInt or SInt types, the return true and fill in the width of them if known.
static LogicalResult verifySubfieldLike(OpTy op)
static void eraseInternalPaths(T op, const llvm::BitVector &portIndices)
static void printFPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
static bool isConstFieldDriven(FIRRTLBaseType type, bool isFlip=false, bool outerTypeIsConst=false)
Checks if the type has any 'const' leaf elements .
static ParseResult parsePrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseParameterList(OpAsmParser &parser, ArrayAttr ¶meters)
Shim to use with assemblyFormat, custom<ParameterList>.
static RetTy emitInferRetTypeError(std::optional< Location > loc, const Twine &message, Args &&...args)
Emit an error if optional location is non-null, return null of return type.
static SmallVector< T > removeElementsAtIndices(ArrayRef< T > input, const llvm::BitVector &indicesToDrop)
Remove elements from the input array corresponding to set bits in indicesToDrop, returning the elemen...
static LogicalResult checkLayerCompatibility(Operation *op, const LayerSet &src, const LayerSet &dst, const Twine &errorMsg, const Twine ¬eMsg=Twine("missing layer requirements"))
static ParseResult parseModulePorts(OpAsmParser &parser, bool hasSSAIdentifiers, bool supportsSymbols, bool supportsDomains, SmallVectorImpl< OpAsmParser::Argument > &entryArgs, SmallVectorImpl< Direction > &portDirections, SmallVectorImpl< Attribute > &portNames, SmallVectorImpl< Attribute > &portTypes, SmallVectorImpl< Attribute > &portAnnotations, SmallVectorImpl< Attribute > &portSyms, SmallVectorImpl< Attribute > &portLocs, SmallVectorImpl< Attribute > &domains)
Parse a list of module ports.
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 parseClassInterface(OpAsmParser &parser, Type &result)
static void printElidePortAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseStopAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseNameKind(OpAsmParser &parser, firrtl::NameKindEnumAttr &result)
A forward declaration for NameKind attribute parser.
static void insertPorts(FModuleLike op, ArrayRef< std::pair< unsigned, PortInfo > > ports, bool supportsInternalPaths=false)
Inserts the given ports.
static size_t getAddressWidth(size_t depth)
static void forceableAsmResultNames(Forceable op, StringRef name, OpAsmSetValueNameFn setNameFn)
Helper for naming forceable declarations (and their optional ref result).
static void printFModuleLikeOp(OpAsmPrinter &p, FModuleLike op)
static void printSubfieldLikeOp(OpTy op, ::mlir::OpAsmPrinter &printer)
SmallSet< SymbolRefAttr, 4, CompareSymbolRefAttr > LayerSet
static bool checkAggConstant(Operation *op, Attribute attr, FIRRTLBaseType type)
static void printClassLike(OpAsmPrinter &p, ClassLike op)
static hw::ModulePort::Direction dirFtoH(Direction dir)
static ParseResult parseOptionalParameters(OpAsmParser &parser, SmallVectorImpl< Attribute > ¶meters)
Parse an parameter list if present.
static MemOp::PortKind getMemPortKindFromType(FIRRTLType type)
Return the kind of port this is given the port type from a 'mem' decl.
static LogicalResult verifyInternalPaths(FModuleLike op, std::optional<::mlir::ArrayAttr > internalPaths)
static void genericAsmResultNames(Operation *op, OpAsmSetValueNameFn setNameFn)
static void printClassInterface(OpAsmPrinter &p, Operation *, ClassType type)
static void printPrintfAttrs(OpAsmPrinter &p, Operation *op, DictionaryAttr attr)
const char * toString(Flow flow)
static bool isLayerSetCompatibleWith(const LayerSet &src, const LayerSet &dst, SmallVectorImpl< SymbolRefAttr > &missing)
Check that the source layers are all present in the destination layers.
static bool isLayerCompatibleWith(mlir::SymbolRefAttr srcLayer, mlir::SymbolRefAttr dstLayer)
Check that the source layer is compatible with the destination layer.
static LayerSet getAmbientLayersFor(Value value)
Get the ambient layer requirements at the definition site of the value.
void buildModuleLike(OpBuilder &builder, OperationState &result, StringAttr name, ArrayRef< PortInfo > ports)
static LayerSet getAmbientLayersAt(Operation *op)
Get the ambient layers active at the given op.
static void printFIRRTLImplicitSSAName(OpAsmPrinter &p, Operation *op, DictionaryAttr attrs)
static ParseResult parseFIRRTLImplicitSSAName(OpAsmParser &parser, NamedAttrList &resultAttrs)
static FIRRTLBaseType inferMuxReturnType(FIRRTLBaseType high, FIRRTLBaseType low, bool isConstCondition, std::optional< Location > loc)
Infer the result type for a multiplexer given its two operand types, which may be aggregates.
static ParseResult parseCircuitOpAttrs(OpAsmParser &parser, NamedAttrList &resultAttrs)
void getAsmBlockArgumentNamesImpl(Operation *op, mlir::Region ®ion, OpAsmSetValueNameFn setNameFn)
Get a special name to use when printing the entry block arguments of the region contained by an opera...
static void printElideAnnotations(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseElidePortAnnotations(OpAsmParser &parser, NamedAttrList &resultAttrs)
Parse an optional attribute dictionary, adding empty 'annotations' and 'portAnnotations' attributes i...
static ParseResult parseFPrintfAttrs(OpAsmParser &p, NamedAttrList &resultAttrs)
static ParseResult parseMemOp(OpAsmParser &parser, NamedAttrList &resultAttrs)
static Attribute fixDomainInfoInsertions(MLIRContext *context, Attribute domainInfoAttr, const SmallVectorImpl< unsigned > &numInserted)
Return an updated domain info Attribute with domain indices updated based on port insertions.
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 bool printModulePorts(OpAsmPrinter &p, Block *block, ArrayRef< bool > portDirections, ArrayRef< Attribute > portNames, ArrayRef< Attribute > portTypes, ArrayRef< Attribute > portAnnotations, ArrayRef< Attribute > portSyms, ArrayRef< Attribute > portLocs, ArrayRef< Attribute > domainInfo)
Print a list of module ports in the following form: in x: !firrtl.uint<1> [{class = "DontTouch}],...
static void printElideEmptyName(OpAsmPrinter &p, Operation *op, DictionaryAttr attr, ArrayRef< StringRef > extraElides={})
static ParseResult parseFModuleLikeOp(OpAsmParser &parser, OperationState &result, bool hasSSAIdentifiers)
static bool isAncestor(Block *block, Block *other)
static Location getLoc(DefSlot slot)
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
static std::optional< APInt > getInt(Value value)
Helper to convert a value to a constant integer if it is one.
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
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 getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
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...
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...
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
bool isConst() const
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)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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.