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"
39 Value memref,
unsigned memoryID,
40 SmallVectorImpl<calyx::PortInfo> &inPorts,
41 SmallVectorImpl<calyx::PortInfo> &outPorts);
48 SmallVectorImpl<Attribute> &sourceLocations);
72template <
typename TGroup>
73TGroup
createGroup(OpBuilder &builder, calyx::ComponentOp compOp, Location loc,
75 mlir::IRRewriter::InsertionGuard guard(builder);
76 builder.setInsertionPointToEnd(compOp.getWiresOp().getBodyBlock());
77 return builder.create<TGroup>(loc, uniqueName.str());
83 calyx::GroupOp groupOp,
84 calyx::ComponentOp componentOp,
85 calyx::RegisterOp ®, Value inputValue);
122 std::optional<Value>
doneOpt();
126 std::variant<calyx::MemoryOp, calyx::SeqMemoryOp, MemoryPortsImpl>
impl;
162 static_assert(std::is_convertible_v<T, Operation *>);
182 static_assert(std::is_convertible_v<T, Operation *>);
239template <
typename Loop>
241 static_assert(std::is_base_of_v<BasicLoopInterface, Loop>);
249 "A register was already registered for the given loop iter_arg "
251 assert(idx < op.getBodyArgs().size());
258 auto it = iterRegs.find(idx);
259 assert(it != iterRegs.end() &&
260 "No iter arg register set for the provided index");
271 Operation *operation = op.getOperation();
273 "A latch group was already set for this loopOp");
281 "No loop latch group was set for this loopOp");
287 Operation *operation = op.getOperation();
289 "Init group(s) was already set for this loopOp");
297 "No init group(s) was set for this loopOp");
304 calyx::ComponentOp componentOp,
306 MutableArrayRef<OpOperand> ops) {
309 std::string groupName =
"assign_" + uniqueSuffix.str();
310 auto groupOp = calyx::createGroup<calyx::GroupOp>(builder, componentOp,
311 op.getLoc(), groupName);
315 for (OpOperand &arg : ops) {
325 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
loopIterRegs;
350 void addBlockArgReg(Block *block, calyx::RegisterOp reg,
unsigned idx);
354 const DenseMap<unsigned, calyx::RegisterOp> &
getBlockArgRegs(Block *block);
406 void addInstance(StringRef calleeName, InstanceOp instanceOp);
409 template <
typename TGroupOp = calyx::GroupInterface>
415 if constexpr (std::is_same_v<TGroupOp, calyx::GroupInterface>)
418 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
419 assert(group &&
"Actual group type differed from expected group type");
426 template <
typename TGroupOp = calyx::GroupInterface>
428 std::optional<TGroupOp> group = findEvaluatingGroup<TGroupOp>(v);
429 assert(group.has_value() &&
"No group evaluating value!");
433 template <
typename T,
typename =
void>
436 template <
typename T>
438 T, std::void_t<decltype(std::declval<T>().getFloatingPointStandard())>>
439 : std::is_same<decltype(std::declval<T>().getFloatingPointStandard()),
440 FloatingPointStandard> {};
442 template <
typename TLibraryOp>
444 TypeRange resTypes) {
445 mlir::IRRewriter::InsertionGuard guard(builder);
447 builder.setInsertionPoint(body, body->begin());
448 std::string name = TLibraryOp::getOperationName().split(
".").second.str();
450 switch (TLibraryOp::getFloatingPointStandard()) {
452 constexpr char prefix[] =
"ieee754.";
453 assert(name.find(prefix) == 0 &&
454 (
"IEEE754 type operation's name must begin with '" +
455 std::string(prefix) +
"'")
457 name.erase(0,
sizeof(prefix) - 1);
458 name = llvm::join_items(
"",
"std_", name,
"FN");
463 return builder.create<TLibraryOp>(loc,
getUniqueName(name), resTypes);
471 auto *extMemDataObj =
extMemData.getAsObject();
472 assert(extMemDataObj &&
"extMemData should be an object");
474 auto &value = (*extMemDataObj)[name.str()];
475 llvm::json::Object *obj = value.getAsObject();
477 value = llvm::json::Object{};
478 obj = value.getAsObject();
480 (*obj)[
"data"] = llvm::json::Value(std::move(data));
483 void setFormat(StringRef name, std::string numType,
bool isSigned,
485 auto *extMemDataObj =
extMemData.getAsObject();
486 assert(extMemDataObj &&
"extMemData should be an object");
488 auto &value = (*extMemDataObj)[name.str()];
489 llvm::json::Object *obj = value.getAsObject();
491 value = llvm::json::Object{};
492 obj = value.getAsObject();
494 (*obj)[
"format"] = llvm::json::Object{
495 {
"numeric_type", numType}, {
"is_signed", isSigned}, {
"width", width}};
509 DenseMap<Block *, DenseMap<Block *, SmallVector<calyx::GroupOp>>>
561 template <
typename T = calyx::ComponentLoweringStateInterface>
563 static_assert(std::is_convertible_v<T, ComponentLoweringStateInterface>);
568 std::tie(it, success) =
572 return static_cast<T *
>(it->second.get());
576 template <
typename ValueOrBlock>
579 llvm::raw_string_ostream os(s);
580 mlir::AsmState asmState(module);
581 v.printAsOperand(os, asmState);
589 mlir::ModuleOp
module;
591 DenseMap<Operation *, std::unique_ptr<ComponentLoweringStateInterface>>
598 DenseMap<const mlir::RewritePattern *, SmallPtrSet<Operation *, 16>>;
605template <
class OpType,
609 using RewritePatternType<OpType>::RewritePatternType;
616 PatternRewriter &rewriter)
const override {
623 rewriter.modifyOpInPlace(
643 PatternRewriter &rewriter)
const = 0;
652 StringRef topLevelFunction);
661 MLIRContext *context, LogicalResult &resRef,
663 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
669 PatternRewriter &rewriter)
const override final;
677 template <
typename T = ComponentLoweringStateInterface>
680 std::is_convertible_v<T, calyx::ComponentLoweringStateInterface>);
683 "Component lowering state should be set during pattern construction");
700 virtual LogicalResult
702 PatternRewriter &rewriter)
const = 0;
720 PatternRewriter &rewriter)
const override;
732 PatternRewriter &)
const override;
742 PatternRewriter &rewriter)
const override;
756 PatternRewriter &rewriter)
const override;
764 PatternRewriter &rewriter)
const override;
773 PatternRewriter &rewriter)
const override;
780 mlir::OpInterfaceRewritePattern> {
787 PatternRewriter &rewriter)
const override;
793 llvm::SmallSetVector<Operation *, 8> &inlinedGroups,
794 calyx::GroupInterface originGroup,
795 calyx::GroupInterface recGroup,
bool doInline)
const;
812 PatternRewriter &rewriter)
const override;
824 PatternRewriter &rewriter)
const override;
834 PatternRewriter &rewriter)
const override;
844 PatternRewriter &rewriter)
const override;
877 if (!type.isSignlessInteger()) {
878 unsigned bitWidth = cast<T>(type).getIntOrFloatBitWidth();
879 return IntegerType::get(type.getContext(), bitWidth);
assert(baseType &&"element must be base type")
virtual Location getLoc()=0
virtual Block * getBodyBlock()=0
virtual ~BasicLoopInterface()
virtual std::optional< int64_t > getBound()=0
virtual Block::BlockArgListType getBodyArgs()=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 DenseMap< Operation *, std::unique_ptr< ComponentLoweringStateInterface > > componentStates
The program associated with this state.
mlir::ModuleOp getModule()
Returns the current program.
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.
T * getState(calyx::ComponentOp op)
Returns the component lowering state associated with op.
const llvm::json::Value & getExtMemData() const
llvm::json::Value & getExtMemData()
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...
void setDataField(StringRef name, llvm::json::Array data)
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()
std::optional< TGroupOp > findEvaluatingGroup(Value v)
Returns the evaluating group or None if not found.
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
void recurseInlineCombGroups(PatternRewriter &rewriter, ComponentLoweringStateInterface &state, llvm::SmallSetVector< Operation *, 8 > &inlinedGroups, calyx::GroupInterface originGroup, calyx::GroupInterface recGroup, bool doInline) const
calyx::CalyxLoweringState & cls
virtual Block * getConditionBlock()=0
virtual Value getConditionValue()=0
calyx::GroupOp getLoopLatchGroup(Loop op)
Retrieve the loop latch group registered for op.
~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.
SmallVector< calyx::GroupOp > getLoopInitGroups(Loop op)
Retrieve the loop init groups registered for op.
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.
const DenseMap< unsigned, calyx::RegisterOp > & getLoopIterRegs(Loop op)
Return a mapping of block argument indices to block argument.
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.
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...
SmallVector< T > getBlockScheduleables(mlir::Block *block)
Returns an ordered list of schedulables which registered themselves to be a result of lowering the bl...
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...
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,...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Removes duplicate EnableOps in parallel operations.
LogicalResult matchAndRewrite(calyx::ParOp parOp, PatternRewriter &rewriter) const override
Removes duplicate EnableOps in static parallel operations.
LogicalResult matchAndRewrite(calyx::StaticParOp parOp, PatternRewriter &rewriter) const override
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