20#include "mlir/IR/Builders.h"
21#include "mlir/IR/BuiltinTypes.h"
22#include "mlir/IR/PatternMatch.h"
23#include "mlir/IR/SymbolTable.h"
32circt::esi::ChannelType ChannelBufferOp::channelType() {
33 return getOutput().getType();
36LogicalResult ChannelBufferOp::verify() {
37 if (getInput().getType().getInner() != getOutput().getType().getInner())
38 return emitOpError(
"input and output data types must match");
39 if (getOutput().getType().getDataDelay() != 0)
40 return emitOpError(
"currently only supports channels with zero data delay");
48LogicalResult SnoopValidReadyOp::verify() {
49 ChannelType type = getInput().getType();
50 if (type.getSignaling() != ChannelSignaling::ValidReady)
51 return emitOpError(
"only supports valid-ready signaling");
52 if (type.getInner() != getData().getType())
53 return emitOpError(
"input and output types must match");
57LogicalResult SnoopValidReadyOp::inferReturnTypes(
58 MLIRContext *context, std::optional<Location> loc, ValueRange operands,
59 DictionaryAttr attrs, mlir::OpaqueProperties properties,
60 mlir::RegionRange regions, SmallVectorImpl<Type> &results) {
61 auto i1 = IntegerType::get(context, 1);
62 results.push_back(i1);
63 results.push_back(i1);
64 results.push_back(cast<ChannelType>(operands[0].getType()).getInner());
72LogicalResult FIFOOp::verify() {
73 if (getOutput().getType().getInner() != getInput().getType().getInner())
74 return emitOpError(
"input and output types must match");
82circt::esi::ChannelType PipelineStageOp::channelType() {
83 return cast<circt::esi::ChannelType>(getInput().getType());
90ParseResult WrapValidReadyOp::parse(OpAsmParser &parser,
91 OperationState &result) {
92 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
94 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
96 if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
97 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
98 parser.parseType(innerOutputType))
101 auto boolType = parser.getBuilder().getI1Type();
103 ChannelType::get(parser.getBuilder().getContext(), innerOutputType);
104 result.addTypes({outputType, boolType});
105 if (parser.resolveOperands(opList, {innerOutputType, boolType},
106 inputOperandsLoc, result.operands))
111void WrapValidReadyOp::print(OpAsmPrinter &p) {
112 p <<
" " << getRawInput() <<
", " << getValid();
113 p.printOptionalAttrDict((*this)->getAttrs());
117void WrapValidReadyOp::build(OpBuilder &b, OperationState &state, Value data,
119 build(b, state, ChannelType::get(state.getContext(),
data.getType()),
120 b.getI1Type(), data, valid);
123LogicalResult WrapValidReadyOp::verify() {
124 mlir::TypedValue<ChannelType> chanOut = getChanOutput();
125 if (chanOut.getType().getSignaling() != ChannelSignaling::ValidReady)
126 return emitOpError(
"only supports valid-ready signaling");
127 if (failed(ChannelType::verifyChannel(chanOut)))
132ParseResult UnwrapValidReadyOp::parse(OpAsmParser &parser,
133 OperationState &result) {
134 llvm::SMLoc inputOperandsLoc = parser.getCurrentLocation();
136 llvm::SmallVector<OpAsmParser::UnresolvedOperand, 2> opList;
138 if (parser.parseOperandList(opList, 2, OpAsmParser::Delimiter::None) ||
139 parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() ||
140 parser.parseType(outputType))
144 ChannelType::get(parser.getBuilder().getContext(), outputType);
146 auto boolType = parser.getBuilder().getI1Type();
148 result.addTypes({inputType.getInner(), boolType});
149 if (parser.resolveOperands(opList, {inputType, boolType}, inputOperandsLoc,
155void UnwrapValidReadyOp::print(OpAsmPrinter &p) {
156 p <<
" " << getChanInput() <<
", " << getReady();
157 p.printOptionalAttrDict((*this)->getAttrs());
158 p <<
" : " << getRawOutput().getType();
161LogicalResult UnwrapValidReadyOp::verify() {
162 if (getChanInput().getType().getSignaling() != ChannelSignaling::ValidReady)
163 return emitOpError(
"only supports valid-ready signaling");
167circt::esi::ChannelType WrapValidReadyOp::channelType() {
168 return cast<circt::esi::ChannelType>(getChanOutput().getType());
171void UnwrapValidReadyOp::build(OpBuilder &b, OperationState &state,
172 Value inChan, Value ready) {
173 auto inChanType = cast<ChannelType>(inChan.getType());
174 build(b, state, inChanType.getInner(), b.getI1Type(), inChan, ready);
177circt::esi::ChannelType UnwrapValidReadyOp::channelType() {
178 return cast<circt::esi::ChannelType>(getChanInput().getType());
181circt::esi::ChannelType WrapFIFOOp::channelType() {
182 return cast<circt::esi::ChannelType>(getChanOutput().getType());
186 Type &chanInputType) {
187 auto loc = p.getCurrentLocation();
189 if (p.parseType(chType))
191 if (chType.getSignaling() != ChannelSignaling::FIFO)
192 return p.emitError(loc,
"can only wrap into FIFO type");
193 dataType = chType.getInner();
194 chanInputType = chType;
203LogicalResult WrapFIFOOp::verify() {
204 if (getChanOutput().getType().getSignaling() != ChannelSignaling::FIFO)
205 return emitOpError(
"only supports FIFO signaling");
209circt::esi::ChannelType UnwrapFIFOOp::channelType() {
210 return cast<circt::esi::ChannelType>(getChanInput().getType());
213LogicalResult UnwrapFIFOOp::verify() {
214 if (getChanInput().getType().getSignaling() != ChannelSignaling::FIFO)
215 return emitOpError(
"only supports FIFO signaling");
220UnwrapFIFOOp::inferReturnTypes(MLIRContext *context, std::optional<Location>,
221 ValueRange operands, DictionaryAttr,
222 mlir::OpaqueProperties, mlir::RegionRange,
223 SmallVectorImpl<Type> &inferredResulTypes) {
224 inferredResulTypes.push_back(
225 cast<ChannelType>(operands[0].getType()).getInner());
226 inferredResulTypes.push_back(
227 IntegerType::get(context, 1, IntegerType::Signless));
234 if (!iface.lookupSymbol<InterfaceSignalOp>(
"valid"))
236 if (!iface.lookupSymbol<InterfaceSignalOp>(
"ready"))
238 auto dataSig = iface.lookupSymbol<InterfaceSignalOp>(
"data");
241 return dataSig.getType();
248 circt::sv::ModportType modportType,
249 ChannelType chanType) {
251 SymbolTable::lookupNearestSymbolFrom<circt::sv::InterfaceModportOp>(
252 op, modportType.getModport());
254 return op->emitError(
"Could not find modport ")
255 << modportType.getModport() <<
" in symbol table.";
256 auto iface = cast<circt::sv::InterfaceOp>(modport->getParentOp());
259 return op->emitOpError(
"Interface is not a valid ESI interface.");
260 if (esiDataType != chanType.getInner())
261 return op->emitOpError(
"Operation specifies ")
262 << chanType <<
" but type inside doesn't match interface data type "
263 << esiDataType <<
".";
267LogicalResult WrapSVInterfaceOp::verify() {
268 auto modportType = cast<circt::sv::ModportType>(getInterfaceSink().getType());
269 auto chanType = cast<ChannelType>(getOutput().getType());
273circt::esi::ChannelType WrapSVInterfaceOp::channelType() {
274 return cast<circt::esi::ChannelType>(getOutput().getType());
277LogicalResult UnwrapSVInterfaceOp::verify() {
279 cast<circt::sv::ModportType>(getInterfaceSource().getType());
280 auto chanType = cast<ChannelType>(getChanInput().getType());
284circt::esi::ChannelType UnwrapSVInterfaceOp::channelType() {
285 return cast<circt::esi::ChannelType>(getChanInput().getType());
288LogicalResult WrapWindow::verify() {
289 hw::UnionType expectedInput = getWindow().getType().getLoweredType();
290 if (expectedInput == getFrame().getType())
292 return emitOpError(
"Expected input type is ") << expectedInput;
296UnwrapWindow::inferReturnTypes(MLIRContext *, std::optional<Location>,
297 ValueRange operands, DictionaryAttr,
298 mlir::OpaqueProperties, mlir::RegionRange,
299 SmallVectorImpl<Type> &inferredReturnTypes) {
300 auto windowType = cast<WindowType>(operands.front().getType());
301 inferredReturnTypes.push_back(windowType.getLoweredType());
308 if (p.parseType(window))
311 frame = window.getLoweredType();
324LogicalResult CosimFromHostEndpointOp::verify() {
325 ChannelType chanType = getFromHost().getType();
326 if (chanType.getSignaling() != ChannelSignaling::ValidReady)
327 return emitOpError(
"only supports valid-ready signaling");
331LogicalResult CosimToHostEndpointOp::verify() {
332 ChannelType chanType = getToHost().getType();
333 if (chanType.getSignaling() != ChannelSignaling::ValidReady)
334 return emitOpError(
"only supports valid-ready signaling");
343static FailureOr<ServiceDeclOpInterface>
345 hw::InnerRefAttr servicePort) {
346 ModuleOp top = op->getParentOfType<mlir::ModuleOp>();
347 SymbolTable &topSyms = symbolTable.getSymbolTable(top);
349 StringAttr modName = servicePort.getModule();
350 auto serviceDecl = topSyms.lookup<ServiceDeclOpInterface>(modName);
352 return op->emitOpError(
"Could not find service declaration ")
353 << servicePort.getModuleRef();
358static FailureOr<ServicePortInfo>
360 hw::InnerRefAttr servicePort) {
362 if (failed(serviceDecl))
364 auto portInfo = serviceDecl->getPortInfo(servicePort.getName());
365 if (failed(portInfo))
366 return op->emitOpError(
"Could not locate port ") << servicePort.getName();
375 if (expected == actual)
379 return TypeSwitch<Type, LogicalResult>(expected)
381 .Case<AnyType>([&](Type) {
return success(); })
383 .Case<ChannelType>([&](ChannelType expectedChannel) {
384 auto actualChannel = dyn_cast<ChannelType>(actual);
388 actualChannel.getInner());
391 .Case<hw::StructType>([&](hw::StructType expectedStruct) {
392 auto actualStruct = dyn_cast<hw::StructType>(actual);
395 auto expectedFields = expectedStruct.getElements();
396 auto actualFields = actualStruct.getElements();
397 if (expectedFields.size() != actualFields.size())
399 for (
auto [efield, afield] : llvm::zip(expectedFields, actualFields)) {
400 if (efield.name != afield.name)
408 .Case<hw::ArrayType>([&](hw::ArrayType expectedArray) {
409 auto actualArray = dyn_cast<hw::ArrayType>(actual);
412 if (expectedArray.getNumElements() != actualArray.getNumElements())
415 actualArray.getElementType());
418 .Case<hw::UnionType>([&](hw::UnionType expectedUnion) {
419 auto actualUnion = dyn_cast<hw::UnionType>(actual);
422 auto expectedElements = expectedUnion.getElements();
423 auto actualElements = actualUnion.getElements();
424 if (expectedElements.size() != actualElements.size())
426 for (
auto [efield, afield] :
427 llvm::zip(expectedElements, actualElements)) {
428 if (efield.name != afield.name)
430 if (efield.offset != afield.offset)
438 .Case<ListType>([&](ListType expectedList) {
439 auto actualList = dyn_cast<ListType>(actual);
443 actualList.getElementType());
446 .Case<WindowType>([&](WindowType expectedWindow) {
447 auto actualWindow = dyn_cast<WindowType>(actual);
451 actualWindow.getInto());
454 .Case<hw::TypeAliasType>([&](hw::TypeAliasType expectedAlias) {
455 auto actualAlias = dyn_cast<hw::TypeAliasType>(actual);
459 actualAlias.getCanonicalType());
462 .Default([&](Type) {
return failure(); });
468 ChannelBundleType svcBundleType,
469 ChannelBundleType reqBundleType,
470 bool skipDirectionCheck) {
471 if (svcBundleType.getChannels().size() != reqBundleType.getChannels().size())
472 return req->emitOpError(
473 "Request port bundle channel count does not match service "
474 "port bundle channel count");
477 DenseMap<StringAttr, BundledChannel> declBundleChannels;
479 declBundleChannels[bc.name] = bc;
483 auto f = declBundleChannels.find(bc.name);
484 if (f == declBundleChannels.end())
485 return req->emitOpError(
486 "Request channel name not found in service port bundle");
487 if (!skipDirectionCheck && f->second.direction != bc.direction)
488 return req->emitOpError(
489 "Request channel direction does not match service "
490 "port bundle channel direction");
493 return req->emitOpError(
494 "Request channel type does not match service port "
495 "bundle channel type")
497 <<
"Service port '" << bc.name.getValue()
498 <<
"' type: " << f->second.type;
507RequestConnectionOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
515LogicalResult ServiceImplementConnReqOp::verifySymbolUses(
516 SymbolTableCollection &symbolTable) {
524void CustomServiceDeclOp::getPortList(SmallVectorImpl<ServicePortInfo> &ports) {
525 for (
auto toClient : getOps<ServiceDeclPortOp>())
527 hw::InnerRefAttr::
get(getSymNameAttr(), toClient.getInnerSymAttr()),
528 toClient.getToClientType()});
537 SmallVectorImpl<Type> &toChannelTypes,
538 SmallVectorImpl<Type> &fromChannelTypes, Type &type) {
540 ChannelBundleType bundleType;
541 if (parser.parseType(bundleType))
546 if (ch.direction == ChannelDirection::to)
547 toChannelTypes.push_back(ch.type);
548 else if (ch.direction == ChannelDirection::from)
549 fromChannelTypes.push_back(ch.type);
551 assert(
false &&
"Channel direction invalid");
554template <
typename T3,
typename T4>
557 p.printType(bundleType);
559void UnpackBundleOp::build(::mlir::OpBuilder &odsBuilder,
560 ::mlir::OperationState &odsState, Value bundle,
561 mlir::ValueRange fromChannels) {
563 cast<ChannelBundleType>(bundle.getType()).getChannels())
564 if (ch.direction == ChannelDirection::to)
565 odsState.addTypes(ch.type);
566 odsState.addOperands(bundle);
567 odsState.addOperands(fromChannels);
570LogicalResult PackBundleOp::verify() {
571 if (!getBundle().hasOneUse())
572 return emitOpError(
"bundles must have exactly one user");
575void PackBundleOp::build(::mlir::OpBuilder &odsBuilder,
576 ::mlir::OperationState &odsState,
577 ChannelBundleType bundleType,
578 mlir::ValueRange toChannels) {
579 odsState.addTypes(bundleType);
580 for (
BundledChannel ch : cast<ChannelBundleType>(bundleType).getChannels())
581 if (ch.direction == ChannelDirection::from)
582 odsState.addTypes(ch.type);
583 odsState.addOperands(toChannels);
586LogicalResult UnpackBundleOp::verify() {
587 if (!getBundle().hasOneUse())
588 return emitOpError(
"bundles must have exactly one user");
593 if (getNumResults() == 0)
595 setNameFn(getResult(0),
"bundle");
596 for (
auto [idx, from] :
llvm::enumerate(
llvm::make_filter_range(
598 return ch.direction == ChannelDirection::from;
600 if (idx + 1 < getNumResults())
601 setNameFn(getResult(idx + 1), from.name.getValue());
605 for (
auto [idx, to] :
llvm::enumerate(
llvm::make_filter_range(
607 return ch.direction == ChannelDirection::to;
609 if (idx < getNumResults())
610 setNameFn(getResult(idx), to.name.getValue());
616LogicalResult ESIPureModuleOp::verify() {
617 ESIDialect *esiDialect = getContext()->getLoadedDialect<ESIDialect>();
618 Block &body = getBody().front();
619 auto channelOrOutput = [](Value v) {
620 if (isa<ChannelType, ChannelBundleType>(v.getType()))
622 if (v.getUsers().empty())
624 return llvm::all_of(v.getUsers(), [](Operation *op) {
625 return isa<ESIPureModuleOutputOp>(op);
629 DenseMap<StringAttr, std::tuple<hw::ModulePort::Direction, Type, Operation *>>
631 for (Operation &op : body.getOperations()) {
632 if (igraph::InstanceOpInterface inst =
633 dyn_cast<igraph::InstanceOpInterface>(op)) {
634 if (llvm::any_of(op.getOperands(), [](Value v) {
635 return !(isa<ChannelType, ChannelBundleType>(v.getType()) ||
636 isa<ESIPureModuleInputOp>(v.getDefiningOp()));
638 return inst.emitOpError(
639 "instances in ESI pure modules can only contain channel ports or "
640 "ports driven by 'input' ops");
641 if (!llvm::all_of(op.getResults(), channelOrOutput))
642 return inst.emitOpError(
643 "instances in ESI pure modules can only contain channel ports or "
644 "drive only 'outputs'");
647 if (op.getDialect() != esiDialect)
648 return op.emitOpError(
"operation not allowed in ESI pure modules");
652 if (
auto port = dyn_cast<ESIPureModuleInputOp>(op)) {
653 auto existing = ports.find(port.getNameAttr());
654 Type portType = port.getResult().getType();
655 if (existing != ports.end()) {
656 auto [dir, type, op] = existing->getSecond();
657 if (dir != hw::ModulePort::Direction::Input || type != portType)
658 return (port.emitOpError(
"port '")
659 << port.getName() <<
"' previously declared as type " << type)
660 .attachNote(op->getLoc());
662 ports[port.getNameAttr()] = std::make_tuple(
663 hw::ModulePort::Direction::Input, portType, port.getOperation());
664 }
else if (
auto port = dyn_cast<ESIPureModuleOutputOp>(op)) {
665 auto existing = ports.find(port.getNameAttr());
666 if (existing != ports.end())
667 return (port.emitOpError(
"port '")
668 << port.getName() <<
"' previously declared")
669 .attachNote(std::get<2>(existing->getSecond())->getLoc());
670 ports[port.getNameAttr()] =
671 std::make_tuple(hw::ModulePort::Direction::Input,
672 port.getValue().getType(), port.getOperation());
678hw::ModuleType ESIPureModuleOp::getHWModuleType() {
679 return hw::ModuleType::get(getContext(), {});
682SmallVector<::circt::hw::PortInfo> ESIPureModuleOp::getPortList() {
return {}; }
684 ::llvm::report_fatal_error(
"not supported");
687size_t ESIPureModuleOp::getNumPorts() {
return 0; }
688size_t ESIPureModuleOp::getNumInputPorts() {
return 0; }
689size_t ESIPureModuleOp::getNumOutputPorts() {
return 0; }
690size_t ESIPureModuleOp::getPortIdForInputId(
size_t) {
691 assert(0 &&
"Out of bounds input port id");
694size_t ESIPureModuleOp::getPortIdForOutputId(
size_t) {
695 assert(0 &&
"Out of bounds output port id");
699SmallVector<Location> ESIPureModuleOp::getAllPortLocs() {
700 SmallVector<Location> retval;
704void ESIPureModuleOp::setAllPortLocsAttrs(ArrayRef<Attribute> locs) {
705 emitError(
"No ports for port locations");
708void ESIPureModuleOp::setAllPortNames(ArrayRef<Attribute> names) {
709 emitError(
"No ports for port naming");
712void ESIPureModuleOp::setAllPortAttrs(ArrayRef<Attribute> attrs) {
713 emitError(
"No ports for port attributes");
716void ESIPureModuleOp::removeAllPortAttrs() {
717 emitError(
"No ports for port attributes)");
720ArrayRef<Attribute> ESIPureModuleOp::getAllPortAttrs() {
return {}; }
722void ESIPureModuleOp::setHWModuleType(hw::ModuleType type) {
723 emitError(
"No ports for port types");
730StringRef ServiceImplRecordOp::getManifestClass() {
731 return getIsEngine() ?
"engine" :
"service";
734void ServiceImplRecordOp::getDetails(SmallVectorImpl<NamedAttribute> &results) {
735 auto *
ctxt = getContext();
737 results.emplace_back(getAppIDAttrName(), getAppIDAttr());
739 results.emplace_back(getServiceAttrName(), getServiceAttr());
740 results.emplace_back(getServiceImplNameAttrName(), getServiceImplNameAttr());
742 for (
auto implDetail : getImplDetailsAttr().getValue())
743 results.push_back(implDetail);
746 SmallVector<Attribute, 8> reqDetails;
747 for (
auto reqDetail : getReqDetails().front().getOps<IsManifestData>())
748 reqDetails.push_back(reqDetail.getDetailsAsDict());
749 results.emplace_back(StringAttr::get(ctxt,
"clientDetails"),
750 ArrayAttr::get(ctxt, reqDetails));
754 Region &reqDetailsRegion) {
755 parser.parseOptionalRegion(reqDetailsRegion);
756 if (reqDetailsRegion.empty())
757 reqDetailsRegion.emplaceBlock();
762 Region &reqDetailsRegion) {
763 if (!reqDetailsRegion.empty() && !reqDetailsRegion.front().empty())
764 p.printRegion(reqDetailsRegion,
false,
768StringRef ServiceImplClientRecordOp::getManifestClass() {
769 return "serviceClient";
771void ServiceImplClientRecordOp::getDetails(
772 SmallVectorImpl<NamedAttribute> &results) {
776 results.emplace_back(getRelAppIDPathAttrName(), getRelAppIDPathAttr());
777 auto servicePort = getServicePortAttr();
778 results.emplace_back(
779 getServicePortAttrName(),
783 NamedAttribute(StringAttr::get(getContext(),
"serviceName"),
784 FlatSymbolRefAttr::get(servicePort.getModule())),
785 NamedAttribute(StringAttr::get(getContext(),
"port"),
786 servicePort.getName()),
788 if (
const auto &channelAssignments = getChannelAssignments())
790 NamedAttribute(getChannelAssignmentsAttrName(), *channelAssignments));
792 if (
const auto &implDetails = getImplDetails())
793 for (
const auto &implDetail : *implDetails)
794 results.push_back(implDetail);
797StringRef ServiceRequestRecordOp::getManifestClass() {
return "clientPort"; }
799void ServiceRequestRecordOp::getDetails(
800 SmallVectorImpl<NamedAttribute> &results) {
801 auto *
ctxt = getContext();
802 results.emplace_back(StringAttr::get(ctxt,
"appID"), getRequestorAttr());
803 results.emplace_back(getTypeIDAttrName(), getTypeIDAttr());
804 auto servicePort = getServicePortAttr();
805 results.emplace_back(
806 getServicePortAttrName(),
810 NamedAttribute(StringAttr::get(getContext(),
"serviceName"),
811 FlatSymbolRefAttr::get(servicePort.getModule())),
812 NamedAttribute(StringAttr::get(getContext(),
"port"),
813 servicePort.getName()),
817StringRef SymbolMetadataOp::getManifestClass() {
return "symInfo"; }
819StringRef SymbolConstantsOp::getManifestClass() {
return "symConsts"; }
820void SymbolConstantsOp::getDetails(SmallVectorImpl<NamedAttribute> &results) {
821 for (
auto &attr : getConstantsAttr())
822 results.push_back(attr);
825#define GET_OP_CLASSES
826#include "circt/Dialect/ESI/ESI.cpp.inc"
828#include "circt/Dialect/ESI/ESIInterfaces.cpp.inc"
assert(baseType &&"element must be base type")
return wrap(CMemoryType::get(unwrap(ctx), baseType, numElements))
static FailureOr< ServiceDeclOpInterface > getServiceDecl(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port declaration op for the specified service decl, port name.
static bool parseInferWindowRet(OpAsmParser &p, Type &frame, Type &windowOut)
Determine the input type ('frame') from the return type ('window').
ParseResult parseWrapFIFOType(OpAsmParser &p, Type &dataType, Type &chanInputType)
static LogicalResult verifySVInterface(Operation *op, circt::sv::ModportType modportType, ChannelType chanType)
Verify that the modport type of 'modportArg' points to an interface which looks like an ESI interface...
void printServiceImplRecordReqDetails(OpAsmPrinter &p, ServiceImplRecordOp, Region &reqDetailsRegion)
static Type getEsiDataType(circt::sv::InterfaceOp iface)
If 'iface' looks like an ESI interface, return the inner data type.
static FailureOr< ServicePortInfo > getServicePortInfo(Operation *op, SymbolTableCollection &symbolTable, hw::InnerRefAttr servicePort)
Get the port info for the specified service decl and port name.
static void printUnPackBundleType(OpAsmPrinter &p, Operation *, T3, T4, Type bundleType)
static ParseResult parseUnPackBundleType(OpAsmParser &parser, SmallVectorImpl< Type > &toChannelTypes, SmallVectorImpl< Type > &fromChannelTypes, Type &type)
static void printInferWindowRet(OpAsmPrinter &p, Operation *, Type, Type window)
void printWrapFIFOType(OpAsmPrinter &p, WrapFIFOOp wrap, Type dataType, Type chanType)
bool parseServiceImplRecordReqDetails(OpAsmParser &parser, Region &reqDetailsRegion)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
LogicalResult checkBundleTypeMatch(Operation *req, ChannelBundleType svcBundleType, ChannelBundleType reqBundleType, bool skipDirectionCheck)
Check that the channels on two bundles match allowing for AnyType in the 'svc' bundle.
LogicalResult checkInnerTypeMatch(Type expected, Type actual)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
function_ref< void(Value, StringRef)> OpAsmSetValueNameFn
Describes a service port.
This holds the name, type, direction of a module's ports.