14 #ifndef CIRCT_DIALECT_CALYX_CALYXLOWERINGUTILS_H
15 #define CIRCT_DIALECT_CALYX_CALYXLOWERINGUTILS_H
21 #include "mlir/Dialect/Arith/IR/Arith.h"
22 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23 #include "mlir/Dialect/Func/IR/FuncOps.h"
24 #include "mlir/Dialect/MemRef/IR/MemRef.h"
25 #include "mlir/Dialect/SCF/IR/SCF.h"
26 #include "mlir/IR/AsmState.h"
27 #include "mlir/IR/PatternMatch.h"
28 #include "llvm/ADT/SmallPtrSet.h"
29 #include "llvm/ADT/TypeSwitch.h"
37 Value memref,
unsigned memoryID,
38 SmallVectorImpl<calyx::PortInfo> &inPorts,
39 SmallVectorImpl<calyx::PortInfo> &outPorts);
46 SmallVectorImpl<Attribute> &sourceLocations);
69 template <
typename TGroup>
70 TGroup
createGroup(OpBuilder &builder, calyx::ComponentOp compOp, Location loc,
72 mlir::IRRewriter::InsertionGuard guard(builder);
73 builder.setInsertionPointToEnd(compOp.getWiresOp().getBodyBlock());
74 return builder.create<TGroup>(loc, uniqueName.str());
80 calyx::GroupOp groupOp,
81 calyx::ComponentOp componentOp,
82 calyx::RegisterOp &
reg, Value inputValue);
119 std::optional<Value>
doneOpt();
123 std::variant<calyx::MemoryOp, calyx::SeqMemoryOp, MemoryPortsImpl>
impl;
157 template <
typename T>
159 static_assert(std::is_convertible_v<T, Operation *>);
177 template <
typename T>
179 static_assert(std::is_convertible_v<T, Operation *>);
196 template <
typename T>
236 template <
typename Loop>
238 static_assert(std::is_base_of_v<BasicLoopInterface, Loop>);
246 "A register was already registered for the given loop iter_arg "
248 assert(idx < op.getBodyArgs().size());
255 auto it = iterRegs.find(idx);
256 assert(it != iterRegs.end() &&
257 "No iter arg register set for the provided index");
268 Operation *operation = op.getOperation();
270 "A latch group was already set for this loopOp");
278 "No loop latch group was set for this loopOp");
284 Operation *operation = op.getOperation();
286 "Init group(s) was already set for this loopOp");
294 "No init group(s) was set for this loopOp");
301 calyx::ComponentOp componentOp,
303 MutableArrayRef<OpOperand> ops) {
306 std::string groupName =
"assign_" + uniqueSuffix.str();
307 auto groupOp = calyx::createGroup<calyx::GroupOp>(builder, componentOp,
308 op.getLoc(), groupName);
312 for (OpOperand &arg : ops) {
322 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
loopIterRegs;
351 const DenseMap<unsigned, calyx::RegisterOp> &
getBlockArgRegs(Block *block);
403 void addInstance(StringRef calleeName, InstanceOp instanceOp);
407 template <
typename TGroupOp = calyx::GroupInterface>
411 if constexpr (std::is_same_v<TGroupOp, calyx::GroupInterface>)
414 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
415 assert(group &&
"Actual group type differed from expected group type");
420 template <
typename TLibraryOp>
422 TypeRange resTypes) {
423 mlir::IRRewriter::InsertionGuard guard(builder);
425 builder.setInsertionPoint(body, body->begin());
426 auto name = TLibraryOp::getOperationName().split(
".").second;
427 return builder.create<TLibraryOp>(loc,
getUniqueName(name), resTypes);
441 DenseMap<Block *, DenseMap<Block *, SmallVector<calyx::GroupOp>>>
489 template <
typename T = calyx::ComponentLoweringStateInterface>
491 static_assert(std::is_convertible_v<T, ComponentLoweringStateInterface>);
496 std::tie(it, success) =
500 return static_cast<T *
>(it->second.get());
504 template <
typename ValueOrBlock>
507 llvm::raw_string_ostream os(s);
508 mlir::AsmState asmState(
module);
509 v.printAsOperand(os, asmState);
519 DenseMap<Operation *, std::unique_ptr<ComponentLoweringStateInterface>>
526 DenseMap<const mlir::RewritePattern *, SmallPtrSet<Operation *, 16>>;
533 template <
class OpType,
537 using RewritePatternType<OpType>::RewritePatternType;
544 PatternRewriter &rewriter)
const override {
551 rewriter.modifyOpInPlace(
571 PatternRewriter &rewriter)
const = 0;
580 StringRef topLevelFunction);
589 MLIRContext *context, LogicalResult &resRef,
591 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
597 PatternRewriter &rewriter)
const override final;
605 template <
typename T = ComponentLoweringStateInterface>
608 std::is_convertible_v<T, calyx::ComponentLoweringStateInterface>);
611 "Component lowering state should be set during pattern construction");
628 virtual LogicalResult
630 PatternRewriter &rewriter)
const = 0;
648 PatternRewriter &rewriter)
const override;
660 PatternRewriter &)
const override;
670 PatternRewriter &rewriter)
const override;
684 PatternRewriter &rewriter)
const override;
691 mlir::OpInterfaceRewritePattern> {
698 PatternRewriter &rewriter)
const override;
704 llvm::SmallSetVector<Operation *, 8> &inlinedGroups,
705 calyx::GroupInterface originGroup,
706 calyx::GroupInterface recGroup,
bool doInline)
const;
723 PatternRewriter &rewriter)
const override;
735 PatternRewriter &rewriter)
const override;
745 PatternRewriter &rewriter)
const override;
755 PatternRewriter &rewriter)
const override;
assert(baseType &&"element must be base type")
virtual std::optional< int64_t > getBound()=0
virtual Location getLoc()=0
virtual ~BasicLoopInterface()
virtual Block::BlockArgListType getBodyArgs()=0
virtual Block * getBodyBlock()=0
Builds registers for each block argument in the program.
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
Builds instance for the calyx.invoke and calyx.group in order to initialize the instance.
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
ComponentOp getCallComponent(mlir::func::CallOp callOp) const
Builds registers for the return statement of the program and constant assignments to the component re...
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)
DenseMap< Operation *, std::unique_ptr< ComponentLoweringStateInterface > > componentStates
Mapping from ComponentOp to component lowering state.
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()
TLibraryOp getNewLibraryOpInstance(OpBuilder &builder, Location loc, TypeRange resTypes)
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.
Converts all index-typed operations and values to i32 values.
LogicalResult partiallyLowerFuncToComp(mlir::func::FuncOp funcOp, PatternRewriter &rewriter) const override
FuncOpPartialLoweringPatterns are patterns which intend to match on FuncOps and then perform their ow...
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.
This pass recursively inlines use-def chains of combinational logic (from non-stateful groups) into g...
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
virtual Value getConditionValue()=0
virtual Block * getConditionBlock()=0
calyx::GroupOp getLoopLatchGroup(Loop op)
Retrieve the loop latch group registered for op.
const DenseMap< unsigned, calyx::RegisterOp > & getLoopIterRegs(Loop op)
Return a mapping of block argument indices to block argument.
~LoopLoweringStateInterface()=default
void setLoopLatchGroup(Loop op, calyx::GroupOp group)
Registers grp to be the loop latch group of op.
calyx::RegisterOp getLoopIterReg(Loop op, unsigned idx)
Return a mapping of block argument indices to block argument.
void addLoopIterReg(Loop op, calyx::RegisterOp reg, unsigned idx)
Register reg as being the idx'th iter_args register for 'op'.
void setLoopInitGroups(Loop op, SmallVector< calyx::GroupOp > groups)
Registers groups to be the loop init groups of op.
DenseMap< Operation *, DenseMap< unsigned, calyx::RegisterOp > > loopIterRegs
A mapping from loop ops to iteration argument registers.
DenseMap< Operation *, calyx::GroupOp > loopLatchGroups
A loop latch group is a group that should be sequentially executed when finishing a loop body.
calyx::GroupOp buildLoopIterArgAssignments(OpBuilder &builder, Loop op, calyx::ComponentOp componentOp, Twine uniqueSuffix, MutableArrayRef< OpOperand > ops)
Creates a new group that assigns the 'ops' values to the iter arg registers of the loop operation.
DenseMap< Operation *, SmallVector< calyx::GroupOp > > loopInitGroups
Loop init groups are to be scheduled before the while operation.
SmallVector< calyx::GroupOp > getLoopInitGroups(Loop op)
Retrieve the loop init groups registered for op.
Base class for partial lowering passes.
virtual LogicalResult partiallyLower(OpType op, PatternRewriter &rewriter) const =0
LogicalResult & partialPatternRes
PatternApplicationState & patternState
PartialLoweringPattern(MLIRContext *ctx, LogicalResult &resRef, PatternApplicationState &patternState)
LogicalResult matchAndRewrite(OpType op, PatternRewriter &rewriter) const override
RepeatOpInterface(Operation *op)
Location getLoc() override
This pass rewrites memory accesses that have a width mismatch.
calyx::CalyxLoweringState & cls
LogicalResult partiallyLower(calyx::AssignOp assignOp, PatternRewriter &rewriter) const override
RewriteMemoryAccesses(MLIRContext *context, LogicalResult &resRef, PatternApplicationState &patternState, calyx::CalyxLoweringState &cls)
Holds common utilities used for scheduling when lowering to Calyx.
SmallVector< T > getBlockScheduleables(mlir::Block *block)
Returns an ordered list of schedulables which registered themselves to be a result of lowering the bl...
void addBlockScheduleable(mlir::Block *block, const T &scheduleable)
Register 'scheduleable' as being generated through lowering 'block'.
DenseMap< mlir::Block *, SmallVector< T > > blockScheduleables
BlockScheduleables is a list of scheduleables that should be sequentially executed when executing the...
Location getLoc() override
WhileOpInterface(Operation *op)
TGroup createGroup(OpBuilder &builder, calyx::ComponentOp compOp, Location loc, Twine uniqueName)
void appendPortsForExternalMemref(PatternRewriter &rewriter, StringRef memName, Value memref, unsigned memoryID, SmallVectorImpl< calyx::PortInfo > &inPorts, SmallVectorImpl< calyx::PortInfo > &outPorts)
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...
Type convIndexType(OpBuilder &builder, Type type)
LogicalResult applyModuleOpConversion(mlir::ModuleOp, StringRef topLevelFunction)
Helper to update the top-level ModuleOp to set the entrypoing function.
WalkResult getCiderSourceLocationMetadata(calyx::ComponentOp component, SmallVectorImpl< Attribute > &sourceLocations)
bool matchConstantOp(Operation *op, APInt &value)
bool noStoresToMemory(Value memoryReference)
Value getComponentOutput(calyx::ComponentOp compOp, unsigned outPortIdx)
bool singleLoadFromMemory(Value memoryReference)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
Removes calyx::CombGroupOps which are unused.
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 > done
std::optional< Value > writeEn
std::optional< Value > writeData
std::optional< bool > isContentEn
std::optional< Value > readData
SmallVector< Value > addrPorts
When building groups which contain accesses to multiple sequential components, a group_done op is cre...
LogicalResult matchAndRewrite(calyx::GroupOp groupOp, PatternRewriter &rewriter) const override
GroupDoneOp's are terminator operations and should therefore be the last operator in a group.
LogicalResult matchAndRewrite(calyx::GroupDoneOp groupDoneOp, PatternRewriter &) const override