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"
30 #include "llvm/Support/JSON.h"
38 Value memref,
unsigned memoryID,
39 SmallVectorImpl<calyx::PortInfo> &inPorts,
40 SmallVectorImpl<calyx::PortInfo> &outPorts);
47 SmallVectorImpl<Attribute> &sourceLocations);
71 template <
typename TGroup>
72 TGroup
createGroup(OpBuilder &builder, calyx::ComponentOp compOp, Location loc,
74 mlir::IRRewriter::InsertionGuard guard(builder);
75 builder.setInsertionPointToEnd(compOp.getWiresOp().getBodyBlock());
76 return builder.create<TGroup>(loc, uniqueName.str());
82 calyx::GroupOp groupOp,
83 calyx::ComponentOp componentOp,
84 calyx::RegisterOp &
reg, Value inputValue);
121 std::optional<Value>
doneOpt();
125 std::variant<calyx::MemoryOp, calyx::SeqMemoryOp, MemoryPortsImpl>
impl;
159 template <
typename T>
161 static_assert(std::is_convertible_v<T, Operation *>);
179 template <
typename T>
181 static_assert(std::is_convertible_v<T, Operation *>);
198 template <
typename T>
238 template <
typename Loop>
240 static_assert(std::is_base_of_v<BasicLoopInterface, Loop>);
248 "A register was already registered for the given loop iter_arg "
250 assert(idx < op.getBodyArgs().size());
257 auto it = iterRegs.find(idx);
258 assert(it != iterRegs.end() &&
259 "No iter arg register set for the provided index");
270 Operation *operation = op.getOperation();
272 "A latch group was already set for this loopOp");
280 "No loop latch group was set for this loopOp");
286 Operation *operation = op.getOperation();
288 "Init group(s) was already set for this loopOp");
296 "No init group(s) was set for this loopOp");
303 calyx::ComponentOp componentOp,
305 MutableArrayRef<OpOperand> ops) {
308 std::string groupName =
"assign_" + uniqueSuffix.str();
309 auto groupOp = calyx::createGroup<calyx::GroupOp>(builder, componentOp,
310 op.getLoc(), groupName);
314 for (OpOperand &arg : ops) {
324 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
loopIterRegs;
353 const DenseMap<unsigned, calyx::RegisterOp> &
getBlockArgRegs(Block *block);
405 void addInstance(StringRef calleeName, InstanceOp instanceOp);
409 template <
typename TGroupOp = calyx::GroupInterface>
413 if constexpr (std::is_same_v<TGroupOp, calyx::GroupInterface>)
416 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
417 assert(group &&
"Actual group type differed from expected group type");
422 template <
typename T,
typename =
void>
425 template <
typename T>
427 T, std::void_t<decltype(std::declval<T>().getFloatingPointStandard())>>
428 : std::is_same<decltype(std::declval<T>().getFloatingPointStandard()),
429 FloatingPointStandard> {};
431 template <
typename TLibraryOp>
433 TypeRange resTypes) {
434 mlir::IRRewriter::InsertionGuard guard(builder);
436 builder.setInsertionPoint(body, body->begin());
437 std::string name = TLibraryOp::getOperationName().split(
".").second.str();
439 switch (TLibraryOp::getFloatingPointStandard()) {
441 constexpr
char prefix[] =
"ieee754.";
442 assert(name.find(prefix) == 0 &&
443 (
"IEEE754 type operation's name must begin with '" +
444 std::string(prefix) +
"'")
446 name.erase(0,
sizeof(prefix) - 1);
447 name = llvm::join_items(
"",
"std_", name,
"FN");
452 return builder.create<TLibraryOp>(loc,
getUniqueName(name), resTypes);
460 auto *extMemDataObj =
extMemData.getAsObject();
461 assert(extMemDataObj &&
"extMemData should be an object");
463 auto &value = (*extMemDataObj)[name.str()];
467 obj = value.getAsObject();
469 (*obj)[
"data"] = llvm::json::Value(std::move(data));
472 void setFormat(StringRef name, std::string numType,
bool isSigned,
474 auto *extMemDataObj =
extMemData.getAsObject();
475 assert(extMemDataObj &&
"extMemData should be an object");
477 auto &value = (*extMemDataObj)[name.str()];
481 obj = value.getAsObject();
484 {
"numeric_type", numType}, {
"is_signed", isSigned}, {
"width", width}};
498 DenseMap<Block *, DenseMap<Block *, SmallVector<calyx::GroupOp>>>
550 template <
typename T = calyx::ComponentLoweringStateInterface>
552 static_assert(std::is_convertible_v<T, ComponentLoweringStateInterface>);
557 std::tie(it, success) =
561 return static_cast<T *
>(it->second.get());
565 template <
typename ValueOrBlock>
568 llvm::raw_string_ostream os(s);
569 mlir::AsmState asmState(
module);
570 v.printAsOperand(os, asmState);
580 DenseMap<Operation *, std::unique_ptr<ComponentLoweringStateInterface>>
587 DenseMap<const mlir::RewritePattern *, SmallPtrSet<Operation *, 16>>;
594 template <
class OpType,
598 using RewritePatternType<OpType>::RewritePatternType;
605 PatternRewriter &rewriter)
const override {
612 rewriter.modifyOpInPlace(
632 PatternRewriter &rewriter)
const = 0;
641 StringRef topLevelFunction);
650 MLIRContext *context, LogicalResult &resRef,
652 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
658 PatternRewriter &rewriter)
const override final;
666 template <
typename T = ComponentLoweringStateInterface>
669 std::is_convertible_v<T, calyx::ComponentLoweringStateInterface>);
672 "Component lowering state should be set during pattern construction");
689 virtual LogicalResult
691 PatternRewriter &rewriter)
const = 0;
709 PatternRewriter &rewriter)
const override;
721 PatternRewriter &)
const override;
731 PatternRewriter &rewriter)
const override;
745 PatternRewriter &rewriter)
const override;
752 mlir::OpInterfaceRewritePattern> {
759 PatternRewriter &rewriter)
const override;
765 llvm::SmallSetVector<Operation *, 8> &inlinedGroups,
766 calyx::GroupInterface originGroup,
767 calyx::GroupInterface recGroup,
bool doInline)
const;
784 PatternRewriter &rewriter)
const override;
796 PatternRewriter &rewriter)
const override;
806 PatternRewriter &rewriter)
const override;
816 PatternRewriter &rewriter)
const override;
847 template <
typename T>
849 if (!type.isSignlessInteger()) {
850 unsigned bitWidth = cast<T>(type).getIntOrFloatBitWidth();
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.
llvm::json::Value & getExtMemData()
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...
void setDataField(StringRef name, llvm::json::Array data)
ComponentLoweringStateInterface(calyx::ComponentOp component)
void registerEvaluatingGroup(Value v, calyx::GroupInterface group)
Register value v as being evaluated when scheduling group.
void setFormat(StringRef name, std::string numType, bool isSigned, unsigned width)
std::optional< calyx::MemoryInterface > isInputPortOfMemory(Value v)
If v is an input to any memory registered within this component, returns the memory.
llvm::json::Value extMemData
A json file to store external global memory data.
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()
const llvm::json::Value & getExtMemData() const
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)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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...
PredicateInfo getPredicateInfo(mlir::arith::CmpFPredicate pred)
Type normalizeType(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)
Type toBitVector(T type)
Performs a bit cast from a non-signless integer type value, such as a floating point value,...
evaluator::ObjectValue Object
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
Predicate information for the floating point comparisons.
SmallVector< InputPorts > inputPorts