18 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
19 #include "mlir/Dialect/MemRef/IR/MemRef.h"
20 #include "mlir/Dialect/SCF/IR/SCF.h"
21 #include "mlir/IR/Matchers.h"
27 using namespace mlir::arith;
33 Value memref,
unsigned memoryID,
34 SmallVectorImpl<calyx::PortInfo> &inPorts,
35 SmallVectorImpl<calyx::PortInfo> &outPorts) {
36 MemRefType memrefType = cast<MemRefType>(memref.getType());
41 auto getMemoryInterfaceAttr = [&](StringRef tag,
42 std::optional<unsigned> addrIdx = {}) {
43 auto attrs = SmallVector<NamedAttribute>{
45 rewriter.getNamedAttr(
"id", rewriter.getI32IntegerAttr(memoryID)),
47 rewriter.getNamedAttr(
"tag", rewriter.getStringAttr(tag))};
48 if (addrIdx.has_value())
51 attrs.push_back(rewriter.getNamedAttr(
52 "addr_idx", rewriter.getI32IntegerAttr(*addrIdx)));
54 return rewriter.getNamedAttr(
"mem", rewriter.getDictionaryAttr(attrs));
59 rewriter.getStringAttr(memName +
"_read_data"),
62 {getMemoryInterfaceAttr(
"read_data")})});
69 {getMemoryInterfaceAttr(
"done")})});
73 rewriter.getStringAttr(memName +
"_write_data"),
76 {getMemoryInterfaceAttr(
"write_data")})});
79 for (
auto dim : enumerate(memrefType.getShape())) {
81 rewriter.getStringAttr(memName +
"_addr" + std::to_string(dim.index())),
85 {getMemoryInterfaceAttr(
"addr", dim.index())})});
90 rewriter.getStringAttr(memName +
"_write_en"), rewriter.getI1Type(),
93 {getMemoryInterfaceAttr(
"write_en")})});
98 SmallVectorImpl<Attribute> &sourceLocations) {
99 Builder builder(component->getContext());
100 return component.getControlOp().walk([&](Operation *op) {
102 return WalkResult::advance();
104 std::string sourceLocation;
105 llvm::raw_string_ostream os(sourceLocation);
106 op->getLoc()->print(os);
107 int64_t position = sourceLocations.size();
108 sourceLocations.push_back(
111 op->setAttr(
"pos", builder.getI64IntegerAttr(position));
112 return WalkResult::advance();
117 return mlir::detail::constant_int_value_binder(&value).match(op);
121 return llvm::count_if(memoryReference.getUses(), [](OpOperand &user) {
122 return isa<mlir::memref::LoadOp>(user.getOwner());
127 return llvm::none_of(memoryReference.getUses(), [](OpOperand &user) {
128 return isa<mlir::memref::StoreOp>(user.getOwner());
133 size_t index = compOp.getInputPortInfo().size() + outPortIdx;
134 assert(index < compOp.getNumArguments() &&
135 "Exceeded number of arguments in the Component");
136 return compOp.getArgument(index);
141 return builder.getI32Type();
146 calyx::GroupOp groupOp,
147 calyx::ComponentOp componentOp,
148 calyx::RegisterOp &
reg,
150 mlir::IRRewriter::InsertionGuard guard(builder);
151 auto loc = inputValue.getLoc();
152 builder.setInsertionPointToEnd(groupOp.getBodyBlock());
153 builder.create<calyx::AssignOp>(loc,
reg.getIn(), inputValue);
154 builder.create<calyx::AssignOp>(
156 builder.create<calyx::GroupDoneOp>(loc,
reg.getDone());
163 MemoryInterface::MemoryInterface() =
default;
180 assert(
readEn.has_value() &&
"Memory does not have readEn");
198 assert(
writeEn.has_value() &&
"Memory does not have writeEn");
204 assert(
done.has_value() &&
"Memory does not have done");
209 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
210 return memOp->readData();
213 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
214 return memOp->readData();
216 return std::get<MemoryPortsImpl>(
impl).readData;
220 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
224 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
228 if (std::get<MemoryPortsImpl>(
impl).readOrContentEn.has_value()) {
229 assert(std::get<MemoryPortsImpl>(
impl).isContentEn.has_value());
230 assert(!std::get<MemoryPortsImpl>(
impl).isContentEn.value());
232 return std::get<MemoryPortsImpl>(
impl).readOrContentEn;
236 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
240 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
241 return memOp->contentEn();
244 if (std::get<MemoryPortsImpl>(
impl).readOrContentEn.has_value()) {
246 assert(std::get<MemoryPortsImpl>(
impl).isContentEn.has_value());
247 assert(std::get<MemoryPortsImpl>(
impl).isContentEn.value());
249 return std::get<MemoryPortsImpl>(
impl).readOrContentEn;
253 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
254 return memOp->writeData();
257 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
258 return memOp->writeData();
260 return std::get<MemoryPortsImpl>(
impl).writeData;
264 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
265 return memOp->writeEn();
268 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
269 return memOp->writeEn();
271 return std::get<MemoryPortsImpl>(
impl).writeEn;
275 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
276 return memOp->done();
279 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
280 return memOp->done();
282 return std::get<MemoryPortsImpl>(
impl).done;
286 if (
auto *memOp = std::get_if<calyx::MemoryOp>(&
impl); memOp) {
287 return memOp->addrPorts();
290 if (
auto *memOp = std::get_if<calyx::SeqMemoryOp>(&
impl); memOp) {
291 return memOp->addrPorts();
293 return std::get<MemoryPortsImpl>(
impl).addrPorts;
307 calyx::ComponentOp component)
308 : component(component) {}
317 calyx::RegisterOp
reg,
320 assert(idx < block->getArguments().size());
324 const DenseMap<unsigned, calyx::RegisterOp> &
330 calyx::GroupOp grp) {
334 ArrayRef<calyx::GroupOp>
340 std::string prefixStr = prefix.str();
343 return (prefix +
"_" + std::to_string(idx)).str();
348 assert(it !=
opNames.end() &&
"A unique name should have been set for op");
355 "A unique name was already set for op");
360 Value v, calyx::GroupInterface group) {
367 "A register was already registered for this index");
378 assert(isa<MemRefType>(memref.getType()));
380 "Memory already registered for memref");
386 assert(isa<MemRefType>(memref.getType()));
388 assert(it !=
memories.end() &&
"No memory registered for memref");
392 std::optional<calyx::MemoryInterface>
395 auto &mem = memIf.getSecond();
396 if (mem.writeEn() == v || mem.writeData() == v ||
397 llvm::any_of(mem.addrPorts(), [=](Value port) { return port == v; }))
404 const DenseMap<unsigned, unsigned> &mapping) {
409 unsigned funcReturnIdx) {
412 "No component return port index recorded for the requested function "
422 InstanceOp instanceOp) {
431 StringRef topLevelFunction)
432 : topLevelFunction(topLevelFunction), module(module) {}
456 StringRef topLevelFunction) {
458 if (moduleOp->hasAttr(
"calyx.entrypoint"))
461 moduleOp->setAttr(
"calyx.entrypoint",
471 MLIRContext *context, LogicalResult &resRef,
473 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
476 functionMapping(map), calyxLoweringState(state) {}
480 PatternRewriter &rewriter)
const {
495 "Component operation should be set during pattern construction");
509 PatternRewriter &rewriter)
const {
510 funcOp.walk([&](Block *block) {
511 for (Value arg : block->getArguments())
515 funcOp.walk([&](Operation *op) {
516 for (Value result : op->getResults()) {
517 Type resType = result.getType();
518 if (!resType.isIndex())
521 result.setType(calyx::convIndexType(rewriter, resType));
522 auto constant = dyn_cast<mlir::arith::ConstantOp>(op);
527 calyx::matchConstantOp(constant, value);
528 rewriter.setInsertionPoint(constant);
529 rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
530 constant, rewriter.getI32IntegerAttr(value.getSExtValue()));
542 PatternRewriter &)
const {
543 Block *block = groupDoneOp->getBlock();
544 if (&block->back() == groupDoneOp)
547 groupDoneOp->moveBefore(groupDoneOp->getBlock(),
548 groupDoneOp->getBlock()->end());
558 PatternRewriter &rewriter)
const {
559 auto groupDoneOps = SmallVector<calyx::GroupDoneOp>(
560 groupOp.getBodyBlock()->getOps<calyx::GroupDoneOp>());
562 if (groupDoneOps.size() <= 1)
566 rewriter.setInsertionPointToEnd(groupDoneOps[0]->getBlock());
567 SmallVector<Value> doneOpSrcs;
568 llvm::transform(groupDoneOps, std::back_inserter(doneOpSrcs),
569 [](calyx::GroupDoneOp op) {
return op.getSrc(); });
570 Value allDone = rewriter.create<
comb::AndOp>(groupDoneOps.front().getLoc(),
574 rewriter.create<calyx::GroupDoneOp>(
576 rewriter.create<
hw::ConstantOp>(groupOp.getLoc(), APInt(1, 1)), allDone);
577 for (
auto groupDoneOp : groupDoneOps)
578 rewriter.eraseOp(groupDoneOp);
589 PatternRewriter &rewriter)
const {
591 combGroupOp->getParentOfType<calyx::ComponentOp>().getControlOp();
592 if (!SymbolTable::symbolKnownUseEmpty(combGroupOp.getSymNameAttr(), control))
595 rewriter.eraseOp(combGroupOp);
610 PatternRewriter &rewriter)
const {
611 auto component = originGroup->getParentOfType<calyx::ComponentOp>();
615 if (SymbolTable::symbolKnownUseEmpty(originGroup.symName(),
616 component.getControlOp()))
621 llvm::SmallSetVector<Operation *, 8> inlinedGroups;
622 inlinedGroups.insert(originGroup);
635 llvm::SmallSetVector<Operation *, 8> &inlinedGroups,
636 calyx::GroupInterface originGroup, calyx::GroupInterface recGroup,
637 bool doInline)
const {
638 inlinedGroups.insert(recGroup);
639 for (
auto assignOp : recGroup.getBody()->getOps<calyx::AssignOp>()) {
642 auto *clonedAssignOp = rewriter.clone(*assignOp.getOperation());
643 clonedAssignOp->moveBefore(originGroup.getBody(),
644 originGroup.getBody()->end());
646 Value src = assignOp.getSrc();
658 if (isa<BlockArgument>(src) ||
659 isa<calyx::RegisterOp, calyx::MemoryOp, calyx::SeqMemoryOp,
661 calyx::DivUPipeLibOp, calyx::DivSPipeLibOp, calyx::RemSPipeLibOp,
662 calyx::RemUPipeLibOp, mlir::scf::WhileOp, calyx::InstanceOp>(
663 src.getDefiningOp()))
666 auto srcCombGroup = dyn_cast<calyx::CombGroupOp>(
670 if (inlinedGroups.count(srcCombGroup))
684 PatternRewriter &rewriter)
const {
685 auto *state =
cls.
getState(assignOp->getParentOfType<calyx::ComponentOp>());
687 Value dest = assignOp.getDest();
688 if (!state->isInputPortOfMemory(dest))
691 Value src = assignOp.getSrc();
692 unsigned srcBits = src.getType().getIntOrFloatBitWidth();
693 unsigned dstBits = dest.getType().getIntOrFloatBitWidth();
694 if (srcBits == dstBits)
697 SmallVector<Type> types = {
698 rewriter.getIntegerType(srcBits),
699 rewriter.getIntegerType(dstBits),
701 mlir::Location loc = assignOp.getLoc();
703 if (srcBits > dstBits)
705 state->getNewLibraryOpInstance<calyx::SliceLibOp>(rewriter, loc, types);
708 state->getNewLibraryOpInstance<calyx::PadLibOp>(rewriter, loc, types);
710 rewriter.setInsertionPoint(assignOp->getBlock(),
711 assignOp->getBlock()->begin());
712 rewriter.create<calyx::AssignOp>(assignOp->getLoc(), newOp->getResult(0),
714 assignOp.setOperand(1, newOp->getResult(1));
725 PatternRewriter &rewriter)
const {
726 funcOp.walk([&](Block *block) {
728 if (block == &block->getParent()->front())
731 for (
auto arg : enumerate(block->getArguments())) {
732 Type argType = arg.value().getType();
733 assert(isa<IntegerType>(argType) &&
"unsupported block argument type");
734 unsigned width = argType.getIntOrFloatBitWidth();
735 std::string index = std::to_string(arg.index());
736 std::string name = loweringState().blockName(block) +
"_arg" + index;
737 auto reg = createRegister(arg.value().getLoc(), rewriter, getComponent(),
739 getState().addBlockArgReg(block, reg, arg.index());
740 arg.value().replaceAllUsesWith(reg.getOut());
752 PatternRewriter &rewriter)
const {
754 for (
auto argType : enumerate(funcOp.getResultTypes())) {
756 assert(isa<IntegerType>(convArgType) &&
"unsupported return type");
757 unsigned width = convArgType.getIntOrFloatBitWidth();
758 std::string name =
"ret_arg" + std::to_string(argType.index());
763 rewriter.setInsertionPointToStart(
765 rewriter.create<calyx::AssignOp>(
780 PatternRewriter &rewriter)
const {
781 funcOp.walk([&](mlir::func::CallOp callOp) {
783 SmallVector<Type, 8> resultTypes;
785 resultTypes.push_back(type);
787 resultTypes.push_back(type);
793 if (!
getState().getInstance(instanceName)) {
794 InstanceOp instanceOp =
797 getState().addInstance(instanceName, instanceOp);
800 OpBuilder::InsertionGuard g(rewriter);
801 rewriter.setInsertionPointToStart(
805 calyx::GroupOp groupOp = rewriter.create<calyx::GroupOp>(
806 callOp.getLoc(),
"init_" + instanceName);
807 rewriter.setInsertionPointToStart(groupOp.getBodyBlock());
808 auto portInfos = instanceOp.getReferencedComponent().getPortInfo();
809 auto results = instanceOp.getResults();
810 for (
const auto &[portInfo, result] : llvm::zip(portInfos, results)) {
812 rewriter.create<calyx::AssignOp>(callOp.getLoc(), result, constantOp);
813 else if (portInfo.hasAttribute(
donePort))
814 rewriter.create<calyx::GroupDoneOp>(callOp.getLoc(), result);
817 WalkResult::advance();
824 std::string callee =
"func_" + callOp.getCallee().str();
826 if (funcOp.getSymName() == callee)
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
virtual ~BasicLoopInterface()
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
ComponentOp getCallComponent(mlir::func::CallOp callOp) const
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
An interface for conversion passes that lower Calyx programs.
std::string irName(ValueOrBlock &v)
Returns a meaningful name for a value within the program scope.
mlir::ModuleOp getModule()
Returns the current program.
CalyxLoweringState(mlir::ModuleOp module, StringRef topLevelFunction)
T * getState(calyx::ComponentOp op)
Returns the component lowering state associated with op.
std::string blockName(Block *b)
Returns a meaningful name for a block within the program scope (removes the ^ prefix from block names...
StringRef getTopLevelFunction() const
Returns the name of the top-level function in the source program.
StringRef topLevelFunction
The name of this top-level function.
mlir::ModuleOp module
The program associated with this state.
const DenseMap< unsigned, calyx::RegisterOp > & getBlockArgRegs(Block *block)
Return a mapping of block argument indices to block argument registers.
void setFuncOpResultMapping(const DenseMap< unsigned, unsigned > &mapping)
Assign a mapping between the source funcOp result indices and the corresponding output port indices o...
DenseMap< Value, calyx::MemoryInterface > memories
A mapping from memref's to their corresponding Calyx memory interface.
TGroupOp getEvaluatingGroup(Value v)
Return the group which evaluates the value v.
void addReturnReg(calyx::RegisterOp reg, unsigned idx)
Register reg as being the idx'th return value register.
calyx::MemoryInterface getMemoryInterface(Value memref)
Returns the memory interface registered for the given memref.
llvm::StringMap< calyx::InstanceOp > instanceMap
A mapping between the callee and the instance.
DenseMap< Block *, DenseMap< Block *, SmallVector< calyx::GroupOp > > > blockArgGroups
Block arg groups is a list of groups that should be sequentially executed when passing control from t...
void setUniqueName(Operation *op, StringRef prefix)
Registers a unique name for a given operation using a provided prefix.
calyx::RegisterOp getReturnReg(unsigned idx)
Returns the idx'th return value register.
std::string getUniqueName(StringRef prefix)
Returns a unique name within compOp with the provided prefix.
calyx::ComponentOp component
The component which this lowering state is associated to.
void registerMemoryInterface(Value memref, const calyx::MemoryInterface &memoryInterface)
Registers a memory interface as being associated with a memory identified by 'memref'.
calyx::ComponentOp getComponentOp()
Returns the calyx::ComponentOp associated with this lowering state.
void addBlockArgReg(Block *block, calyx::RegisterOp reg, unsigned idx)
Register reg as being the idx'th argument register for block.
InstanceOp getInstance(StringRef calleeName)
The instance is obtained from the name of the callee.
unsigned getFuncOpResultMapping(unsigned funcReturnIdx)
Get the output port index of this component for which the funcReturnIdx of the original function maps...
DenseMap< unsigned, unsigned > funcOpResultMapping
A mapping between the source funcOp result indices and the corresponding output port indices of this ...
void addInstance(StringRef calleeName, InstanceOp instanceOp)
Put the name of the callee and the instance of the call into map.
DenseMap< Value, calyx::GroupInterface > valueGroupAssigns
A mapping between SSA values and the groups which assign them.
std::map< std::string, unsigned > prefixIdMap
A mapping of string prefixes and the current uniqueness counter for that prefix.
ArrayRef< calyx::GroupOp > getBlockArgGroups(Block *from, Block *to)
Returns a list of groups to be evaluated to perform the block argument register assignments when tran...
ComponentLoweringStateInterface(calyx::ComponentOp component)
void registerEvaluatingGroup(Value v, calyx::GroupInterface group)
Register value v as being evaluated when scheduling group.
std::optional< calyx::MemoryInterface > isInputPortOfMemory(Value v)
If v is an input to any memory registered within this component, returns the memory.
void addBlockArgGroup(Block *from, Block *to, calyx::GroupOp grp)
Register 'grp' as a group which performs block argument register transfer when transitioning from bas...
~ComponentLoweringStateInterface()
DenseMap< Block *, DenseMap< unsigned, calyx::RegisterOp > > blockArgRegs
A mapping from blocks to block argument registers.
DenseMap< unsigned, calyx::RegisterOp > returnRegs
A mapping from return value indexes to return value registers.
std::map< Operation *, std::string > opNames
A mapping from Operations and previously assigned unique name of the op.
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
calyx::ComponentOp getComponent() const
Returns the component operation associated with the currently executing partial lowering.
CalyxLoweringState & calyxLoweringState
ComponentLoweringStateInterface * componentLoweringState
DenseMap< mlir::func::FuncOp, calyx::ComponentOp > & functionMapping
virtual LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const =0
CalyxLoweringState & loweringState() const
Return the calyx lowering state for this pattern.
FuncOpPartialLoweringPattern(MLIRContext *context, LogicalResult &resRef, PatternApplicationState &patternState, DenseMap< mlir::func::FuncOp, calyx::ComponentOp > &map, calyx::CalyxLoweringState &state)
LogicalResult partiallyLower(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override final
Entry point to initialize the state of this class and conduct the partial lowering.
LogicalResult partiallyLower(calyx::GroupInterface originGroup, PatternRewriter &rewriter) const override
InlineCombGroups(MLIRContext *context, LogicalResult &resRef, PatternApplicationState &patternState, calyx::CalyxLoweringState &pls)
void recurseInlineCombGroups(PatternRewriter &rewriter, ComponentLoweringStateInterface &state, llvm::SmallSetVector< Operation *, 8 > &inlinedGroups, calyx::GroupInterface originGroup, calyx::GroupInterface recGroup, bool doInline) const
calyx::CalyxLoweringState & cls
Base class for partial lowering passes.
calyx::CalyxLoweringState & cls
LogicalResult partiallyLower(calyx::AssignOp assignOp, PatternRewriter &rewriter) const override
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
void appendPortsForExternalMemref(PatternRewriter &rewriter, StringRef memName, Value memref, unsigned memoryID, SmallVectorImpl< calyx::PortInfo > &inPorts, SmallVectorImpl< calyx::PortInfo > &outPorts)
static constexpr std::string_view donePort
void buildAssignmentsForRegisterWrite(OpBuilder &builder, calyx::GroupOp groupOp, calyx::ComponentOp componentOp, calyx::RegisterOp ®, Value inputValue)
Creates register assignment operations within the provided groupOp.
DenseMap< const mlir::RewritePattern *, SmallPtrSet< Operation *, 16 > > PatternApplicationState
Extra state that is passed to all PartialLoweringPatterns so they can record when they have run on an...
bool isControlLeafNode(Operation *op)
Type convIndexType(OpBuilder &builder, Type type)
LogicalResult applyModuleOpConversion(mlir::ModuleOp, StringRef topLevelFunction)
Helper to update the top-level ModuleOp to set the entrypoing function.
static constexpr std::string_view resetPort
WalkResult getCiderSourceLocationMetadata(calyx::ComponentOp component, SmallVectorImpl< Attribute > &sourceLocations)
bool matchConstantOp(Operation *op, APInt &value)
unsigned handleZeroWidth(int64_t dim)
hw::ConstantOp createConstant(Location loc, OpBuilder &builder, ComponentOp component, size_t width, size_t value)
A helper function to create constants in the HW dialect.
calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, ComponentOp component, size_t width, Twine prefix)
Creates a RegisterOp, with input and output port bit widths defined by width.
bool noStoresToMemory(Value memoryReference)
Value getComponentOutput(calyx::ComponentOp compOp, unsigned outPortIdx)
bool singleLoadFromMemory(Value memoryReference)
calyx::InstanceOp createInstance(Location loc, OpBuilder &builder, ComponentOp component, SmallVectorImpl< Type > &resultTypes, StringRef instanceName, StringRef componentName)
A helper function to create calyx.instance operation.
static constexpr std::string_view goPort
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
LogicalResult matchAndRewrite(calyx::CombGroupOp combGroupOp, PatternRewriter &rewriter) const override
std::optional< Value > contentEnOpt()
std::variant< calyx::MemoryOp, calyx::SeqMemoryOp, MemoryPortsImpl > impl
std::optional< Value > writeDataOpt()
std::optional< Value > readEnOpt()
std::optional< Value > readDataOpt()
std::optional< Value > doneOpt()
std::optional< Value > writeEnOpt()
std::optional< Value > readOrContentEn
std::optional< Value > writeEn
std::optional< bool > isContentEn
LogicalResult matchAndRewrite(calyx::GroupOp groupOp, PatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(calyx::GroupDoneOp groupDoneOp, PatternRewriter &) const override
This holds information about the port for either a Component or Cell.