20#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
21#include "mlir/Conversion/LLVMCommon/Pattern.h"
22#include "mlir/Dialect/Arith/IR/Arith.h"
23#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
24#include "mlir/Dialect/Func/IR/FuncOps.h"
25#include "mlir/Dialect/MemRef/IR/MemRef.h"
26#include "mlir/IR/AsmState.h"
27#include "mlir/IR/Matchers.h"
28#include "mlir/Pass/Pass.h"
29#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
30#include "llvm/ADT/TypeSwitch.h"
36#define GEN_PASS_DEF_LOOPSCHEDULETOCALYX
37#include "circt/Conversion/Passes.h.inc"
42using namespace mlir::arith;
43using namespace mlir::cf;
45using namespace circt::loopschedule;
48namespace pipelinetocalyx {
68 return getOperation().getCondBlock().getTerminator()->getOperand(0);
89using Scheduleable = std::variant<calyx::GroupOp, PipelineScheduleable>;
97 calyx::GroupInterface group) {
103 template <
typename TGroupOp = calyx::GroupInterface>
109 if constexpr (std::is_same<TGroupOp, calyx::GroupInterface>::value)
112 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
113 assert(group &&
"Actual group type differed from expected group type");
120 assert(idx < stage->getNumResults());
125 const DenseMap<unsigned, calyx::RegisterOp> &
133 auto opStage = dyn_cast<LoopSchedulePipelineStageOp>(value.getDefiningOp());
134 if (opStage ==
nullptr)
137 auto opResult = cast<OpResult>(value);
138 unsigned int opNumber = opResult.getResultNumber();
140 return stageRegisters.find(opNumber)->second;
161 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
162 PatternRewriter::InsertionGuard g(rewriter);
163 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
164 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
165 for (
size_t j = 0; j < i + 1; ++j)
166 for (
auto group : stages[j])
167 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
174 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
175 PatternRewriter::InsertionGuard g(rewriter);
176 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
177 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
178 for (
size_t j = i, f = stages.size(); j < f; ++j)
179 for (
auto group : stages[j])
180 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
191 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
pipelineRegs;
223 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
227 PatternRewriter &rewriter)
const override {
230 bool opBuiltSuccessfully =
true;
231 funcOp.walk([&](Operation *_op) {
232 opBuiltSuccessfully &=
233 TypeSwitch<mlir::Operation *, bool>(_op)
234 .template Case<arith::ConstantOp, ReturnOp, BranchOpInterface,
236 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
239 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp,
240 AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp, MulIOp,
241 DivUIOp, RemUIOp, IndexCastOp,
243 LoopScheduleTerminatorOp>(
244 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
246 LoopScheduleRegisterOp,
247 LoopSchedulePipelineStageOp>([&](
auto) {
251 .Default([&](
auto op) {
252 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
256 return opBuiltSuccessfully ? WalkResult::advance()
257 : WalkResult::interrupt();
260 return success(opBuiltSuccessfully);
265 LogicalResult
buildOp(PatternRewriter &rewriter,
266 BranchOpInterface brOp)
const;
267 LogicalResult
buildOp(PatternRewriter &rewriter,
268 arith::ConstantOp constOp)
const;
269 LogicalResult
buildOp(PatternRewriter &rewriter, AddIOp op)
const;
270 LogicalResult
buildOp(PatternRewriter &rewriter, SubIOp op)
const;
271 LogicalResult
buildOp(PatternRewriter &rewriter, MulIOp op)
const;
272 LogicalResult
buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
273 LogicalResult
buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
274 LogicalResult
buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
275 LogicalResult
buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
276 LogicalResult
buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
277 LogicalResult
buildOp(PatternRewriter &rewriter, AndIOp op)
const;
278 LogicalResult
buildOp(PatternRewriter &rewriter, OrIOp op)
const;
279 LogicalResult
buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
280 LogicalResult
buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
281 LogicalResult
buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
282 LogicalResult
buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
283 LogicalResult
buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
284 LogicalResult
buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
285 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
286 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
287 LogicalResult
buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
288 LogicalResult
buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
289 LogicalResult
buildOp(PatternRewriter &rewriter,
290 LoopScheduleTerminatorOp op)
const;
294 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
296 TypeRange srcTypes, TypeRange dstTypes)
const {
297 SmallVector<Type> types;
298 llvm::append_range(types, srcTypes);
299 llvm::append_range(types, dstTypes);
302 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
303 rewriter, op.getLoc(), types);
305 auto directions = calyxOp.portDirections();
306 SmallVector<Value, 4> opInputPorts;
307 SmallVector<Value, 4> opOutputPorts;
308 for (
auto dir : enumerate(directions)) {
310 opInputPorts.push_back(calyxOp.getResult(dir.index()));
312 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
315 opInputPorts.size() == op->getNumOperands() &&
316 opOutputPorts.size() == op->getNumResults() &&
317 "Expected an equal number of in/out ports in the Calyx library op with "
318 "respect to the number of operands/results of the source operation.");
321 auto group = createGroupForOp<TGroupOp>(rewriter, op);
322 rewriter.setInsertionPointToEnd(group.getBodyBlock());
323 for (
auto dstOp : enumerate(opInputPorts)) {
324 Value srcOp = op->getOperand(dstOp.index());
325 std::optional<calyx::RegisterOp> pipelineRegister =
326 getState<ComponentLoweringState>().getPipelineRegister(srcOp);
327 if (pipelineRegister.has_value())
328 srcOp = pipelineRegister->getOut();
329 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(), srcOp);
333 for (
auto res : enumerate(opOutputPorts)) {
334 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
336 op->getResult(res.index()).replaceAllUsesWith(res.value());
343 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
345 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
346 rewriter, op, op.getOperandTypes(), op->getResultTypes());
350 template <
typename TGroupOp>
352 Block *block = op->getBlock();
353 auto groupName = getState<ComponentLoweringState>().getUniqueName(
355 return calyx::createGroup<TGroupOp>(
356 rewriter, getState<ComponentLoweringState>().getComponentOp(),
357 op->getLoc(), groupName);
362 template <
typename TOpType,
typename TSrcOp>
364 TOpType opPipe, Value out)
const {
365 StringRef opName = TSrcOp::getOperationName().split(
".").second;
366 Location loc = op.getLoc();
367 Type width = op.getResult().getType();
369 op.getResult().replaceAllUsesWith(out);
370 auto reg = createRegister(
371 op.getLoc(), rewriter,
getComponent(), width.getIntOrFloatBitWidth(),
372 getState<ComponentLoweringState>().getUniqueName(opName));
374 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
375 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
378 rewriter.setInsertionPointToEnd(group.getBodyBlock());
379 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
380 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
382 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), out);
384 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(), opPipe.getDone());
385 rewriter.create<calyx::AssignOp>(
389 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
392 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
393 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
395 getState<ComponentLoweringState>().registerEvaluatingGroup(
396 opPipe.getRight(), group);
404 calyx::GroupInterface group,
406 Operation::operand_range addressValues)
const {
407 IRRewriter::InsertionGuard guard(rewriter);
408 rewriter.setInsertionPointToEnd(group.getBody());
409 auto addrPorts = memoryInterface.
addrPorts();
410 if (addressValues.empty()) {
412 addrPorts.size() == 1 &&
413 "We expected a 1 dimensional memory of size 1 because there were no "
414 "address assignment values");
416 rewriter.create<calyx::AssignOp>(
420 assert(addrPorts.size() == addressValues.size() &&
421 "Mismatch between number of address ports of the provided memory "
422 "and address assignment values");
423 for (
auto address : enumerate(addressValues))
424 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
431 memref::LoadOp loadOp)
const {
432 Value memref = loadOp.getMemref();
433 auto memoryInterface =
434 getState<ComponentLoweringState>().getMemoryInterface(memref);
442 auto combGroup = createGroupForOp<calyx::CombGroupOp>(rewriter, loadOp);
444 loadOp.getIndices());
455 getState<ComponentLoweringState>().registerEvaluatingGroup(
456 loadOp.getResult(), combGroup);
458 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
460 loadOp.getIndices());
470 auto reg = createRegister(
472 loadOp.getMemRefType().getElementTypeBitWidth(),
473 getState<ComponentLoweringState>().getUniqueName(
"load"));
475 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
476 reg, memoryInterface.readData());
477 loadOp.getResult().replaceAllUsesWith(reg.getOut());
478 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
485 memref::StoreOp storeOp)
const {
486 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
487 storeOp.getMemref());
488 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
492 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
495 storeOp.getIndices());
496 rewriter.setInsertionPointToEnd(group.getBodyBlock());
497 rewriter.create<calyx::AssignOp>(
498 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
499 rewriter.create<calyx::AssignOp>(
500 storeOp.getLoc(), memoryInterface.writeEn(),
501 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
502 if (memoryInterface.contentEnOpt().has_value()) {
504 rewriter.create<calyx::AssignOp>(
505 storeOp.getLoc(), memoryInterface.contentEn(),
506 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
508 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
510 getState<ComponentLoweringState>().registerNonPipelineOperations(storeOp,
518 Location loc = mul.getLoc();
519 Type width = mul.getResult().getType(), one = rewriter.getI1Type();
521 getState<ComponentLoweringState>()
522 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
523 rewriter, loc, {one, one, one, width, width, width, one});
524 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
525 rewriter, mul, mulPipe,
531 Location loc = div.getLoc();
532 Type width = div.getResult().getType(), one = rewriter.getI1Type();
534 getState<ComponentLoweringState>()
535 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
536 rewriter, loc, {one, one, one, width, width, width, width, one});
537 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
538 rewriter, div, divPipe,
544 Location loc = rem.getLoc();
545 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
547 getState<ComponentLoweringState>()
548 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
549 rewriter, loc, {one, one, one, width, width, width, width, one});
550 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
551 rewriter, rem, remPipe,
555template <
typename TAllocOp>
557 PatternRewriter &rewriter, TAllocOp allocOp) {
558 rewriter.setInsertionPointToStart(
560 MemRefType memtype = allocOp.getType();
561 SmallVector<int64_t> addrSizes;
562 SmallVector<int64_t> sizes;
563 for (int64_t dim : memtype.getShape()) {
564 sizes.push_back(dim);
569 if (sizes.empty() && addrSizes.empty()) {
571 addrSizes.push_back(1);
573 auto memoryOp = rewriter.create<calyx::MemoryOp>(
575 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
578 memoryOp->setAttr(
"external",
579 IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));
586 memref::AllocOp allocOp)
const {
587 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
591 memref::AllocaOp allocOp)
const {
592 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
596 LoopScheduleTerminatorOp term)
const {
597 if (term.getOperands().size() == 0)
601 auto *pipeline = term->getParentOp();
602 for (
size_t i = 0, e = pipeline->getNumResults(); i < e; ++i)
603 pipeline->getResult(i).replaceAllUsesWith(term.getResults()[i]);
609 BranchOpInterface brOp)
const {
614 Block *srcBlock = brOp->getBlock();
615 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
616 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
617 if (succOperands.empty())
622 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
623 brOp.getLoc(), groupName);
625 auto dstBlockArgRegs =
626 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
628 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
629 auto reg = dstBlockArgRegs[arg.index()];
632 getState<ComponentLoweringState>().getComponentOp(), reg,
637 getState<ComponentLoweringState>().addBlockArgGroup(
638 srcBlock, succBlock.value(), groupOp);
646 ReturnOp retOp)
const {
647 if (retOp.getNumOperands() == 0)
650 std::string groupName =
651 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
652 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
653 retOp.getLoc(), groupName);
654 for (
auto op : enumerate(retOp.getOperands())) {
655 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
657 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
661 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
667 arith::ConstantOp constOp)
const {
671 auto hwConstOp = rewriter.replaceOpWithNewOp<
hw::ConstantOp>(constOp, value);
679 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
683 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
687 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
691 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
695 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
699 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
703 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
707 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
712 switch (op.getPredicate()) {
713 case CmpIPredicate::eq:
714 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
715 case CmpIPredicate::ne:
716 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
717 case CmpIPredicate::uge:
718 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
719 case CmpIPredicate::ult:
720 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
721 case CmpIPredicate::ugt:
722 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
723 case CmpIPredicate::ule:
724 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
725 case CmpIPredicate::sge:
726 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
727 case CmpIPredicate::slt:
728 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
729 case CmpIPredicate::sgt:
730 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
731 case CmpIPredicate::sle:
732 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
734 llvm_unreachable(
"unsupported comparison predicate");
738 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
739 rewriter, op, {op.getOperand().getType()}, {op.getType()});
743 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
744 rewriter, op, {op.getOperand().getType()}, {op.getType()});
748 IndexCastOp op)
const {
751 unsigned targetBits = targetType.getIntOrFloatBitWidth();
752 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
753 LogicalResult res = success();
755 if (targetBits == sourceBits) {
758 op.getResult().replaceAllUsesWith(op.getOperand());
761 if (sourceBits > targetBits)
762 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
763 rewriter, op, {sourceType}, {targetType});
765 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
766 rewriter, op, {sourceType}, {targetType});
768 rewriter.eraseOp(op);
774 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
778 PatternRewriter &rewriter)
const override {
781 DenseMap<Value, unsigned> funcOpArgRewrites;
785 DenseMap<unsigned, unsigned> funcOpResultMapping;
793 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
797 SmallVector<calyx::PortInfo> inPorts, outPorts;
798 FunctionType funcType = funcOp.getFunctionType();
799 unsigned extMemCounter = 0;
800 for (
auto arg : enumerate(funcOp.getArguments())) {
801 if (isa<MemRefType>(arg.value().getType())) {
804 "ext_mem" + std::to_string(extMemoryCompPortIndices.size());
805 extMemoryCompPortIndices[arg.value()] = {inPorts.size(),
808 extMemCounter++, inPorts, outPorts);
811 auto inName =
"in" + std::to_string(arg.index());
812 funcOpArgRewrites[arg.value()] = inPorts.size();
814 rewriter.getStringAttr(inName),
817 DictionaryAttr::get(rewriter.getContext(), {})});
820 for (
auto res : enumerate(funcType.getResults())) {
821 funcOpResultMapping[res.index()] = outPorts.size();
823 rewriter.getStringAttr(
"out" + std::to_string(res.index())),
825 DictionaryAttr::get(rewriter.getContext(), {})});
830 auto ports = inPorts;
831 llvm::append_range(ports, outPorts);
835 auto compOp = rewriter.create<calyx::ComponentOp>(
836 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
839 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
847 for (
auto &mapping : funcOpArgRewrites)
848 mapping.getFirst().replaceAllUsesWith(
849 compOp.getArgument(mapping.getSecond()));
852 for (
auto extMemPortIndices : extMemoryCompPortIndices) {
856 unsigned inPortsIt = extMemPortIndices.getSecond().first;
857 unsigned outPortsIt = extMemPortIndices.getSecond().second +
858 compOp.getInputPortInfo().size();
859 extMemPorts.
readData = compOp.getArgument(inPortsIt++);
860 extMemPorts.
done = compOp.getArgument(inPortsIt);
861 extMemPorts.
writeData = compOp.getArgument(outPortsIt++);
862 unsigned nAddresses =
863 cast<MemRefType>(extMemPortIndices.getFirst().getType())
866 for (
unsigned j = 0; j < nAddresses; ++j)
867 extMemPorts.
addrPorts.push_back(compOp.getArgument(outPortsIt++));
868 extMemPorts.
writeEn = compOp.getArgument(outPortsIt);
872 compState->registerMemoryInterface(extMemPortIndices.getFirst(),
885 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
889 PatternRewriter &rewriter)
const override {
890 LogicalResult res = success();
891 funcOp.walk([&](Operation *op) {
892 if (!isa<LoopSchedulePipelineOp>(op))
893 return WalkResult::advance();
897 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
905 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
906 std::string name = getState<ComponentLoweringState>()
909 "_arg" + std::to_string(arg.index());
911 createRegister(arg.value().getLoc(), rewriter,
getComponent(),
912 arg.value().getType().getIntOrFloatBitWidth(), name);
913 getState<ComponentLoweringState>().addLoopIterReg(whileOp, reg,
915 arg.value().replaceAllUsesWith(reg.getOut());
919 ->getArgument(arg.index())
920 .replaceAllUsesWith(reg.getOut());
924 SmallVector<calyx::GroupOp> initGroups;
925 auto numOperands = whileOp.
getOperation()->getNumOperands();
926 for (
size_t i = 0; i < numOperands; ++i) {
928 getState<ComponentLoweringState>().buildLoopIterArgAssignments(
930 getState<ComponentLoweringState>().getComponentOp(),
931 getState<ComponentLoweringState>().getUniqueName(
933 "_init_" + std::to_string(i),
935 initGroups.push_back(initGroupOp);
940 getState<ComponentLoweringState>().addBlockScheduleable(
945 return WalkResult::advance();
953 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
957 PatternRewriter &rewriter)
const override {
958 funcOp.walk([&](LoopScheduleRegisterOp op) {
960 auto *parent = op->getParentOp();
961 auto stage = dyn_cast<LoopSchedulePipelineStageOp>(parent);
966 for (
auto &operand : op->getOpOperands()) {
967 unsigned i = operand.getOperandNumber();
970 Value stageResult = stage.getResult(i);
971 bool isIterArg =
false;
972 for (
auto &use : stageResult.getUses()) {
973 if (
auto term = dyn_cast<LoopScheduleTerminatorOp>(use.getOwner())) {
974 if (use.getOperandNumber() < term.getIterArgs().size()) {
976 dyn_cast<LoopSchedulePipelineOp>(stage->getParentOp()));
977 auto reg = getState<ComponentLoweringState>().getLoopIterReg(
978 whileOp, use.getOperandNumber());
979 getState<ComponentLoweringState>().addPipelineReg(stage, reg, i);
988 Value value = operand.get();
989 Type resultType = value.getType();
990 assert(isa<IntegerType>(resultType) &&
991 "unsupported pipeline result type");
992 auto name = SmallString<20>(
"stage_");
993 name += std::to_string(stage.getStageNumber());
994 name +=
"_register_";
995 name += std::to_string(i);
996 unsigned width = resultType.getIntOrFloatBitWidth();
997 auto reg = createRegister(value.getLoc(), rewriter,
getComponent(),
999 getState<ComponentLoweringState>().addPipelineReg(stage, reg, i);
1013 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1017 PatternRewriter &rewriter)
const override {
1020 pipeline.getStagesBlock().getOps<LoopSchedulePipelineStageOp>())
1028 LoopSchedulePipelineStageOp stage,
1029 PatternRewriter &rewriter)
const {
1031 auto pipelineRegisters =
1032 getState<ComponentLoweringState>().getPipelineRegs(stage);
1036 size_t numStages = whileOp.getStagesBlock().getOperations().size() - 1;
1040 SmallVector<StringAttr> prologueGroups, epilogueGroups;
1041 auto &state = getState<ComponentLoweringState>();
1043 auto updatePrologueAndEpilogue = [&](calyx::GroupOp group) {
1045 state.addBlockScheduleable(stage->getBlock(), group);
1053 unsigned stageNumber = stage.getStageNumber();
1054 if (stageNumber < numStages - 1)
1055 prologueGroups.push_back(group.getSymNameAttr());
1056 if (stageNumber > 0)
1057 epilogueGroups.push_back(group.getSymNameAttr());
1060 MutableArrayRef<OpOperand> operands =
1061 stage.getBodyBlock().getTerminator()->getOpOperands();
1062 bool isStageWithNoPipelinedValues =
1063 operands.empty() && !stage.getBodyBlock().empty();
1064 if (isStageWithNoPipelinedValues) {
1067 for (
auto &op : stage.getBodyBlock())
1068 if (
auto group = state.getNonPipelinedGroupFrom<calyx::GroupOp>(&op))
1069 updatePrologueAndEpilogue(*group);
1072 for (
auto &operand : operands) {
1073 unsigned i = operand.getOperandNumber();
1074 Value value = operand.get();
1077 calyx::RegisterOp pipelineRegister = pipelineRegisters[i];
1078 if (std::optional<calyx::RegisterOp> pr =
1079 state.getPipelineRegister(value)) {
1080 value = pr->getOut();
1083 calyx::GroupOp group;
1085 std::optional<calyx::GroupInterface> evaluatingGroup =
1086 state.findEvaluatingGroup(value);
1087 if (!evaluatingGroup.has_value()) {
1088 if (value.getDefiningOp<calyx::RegisterOp>() ==
nullptr) {
1090 llvm::errs() <<
"unexpected: input value: " << value <<
", in stage "
1091 << stage.getStageNumber() <<
" register " << i
1092 <<
" is not a register and was not previously "
1093 "evaluated in a Calyx group. Please open an issue.\n";
1094 return LogicalResult::failure();
1098 std::string groupName = state.getUniqueName(
1100 group = calyx::createGroup<calyx::GroupOp>(
1101 rewriter, state.getComponentOp(), pipelineRegister->getLoc(),
1104 rewriter, group, state.getComponentOp(), pipelineRegister, value);
1109 dyn_cast<calyx::CombGroupOp>(evaluatingGroup->getOperation());
1110 group = combGroup ==
nullptr
1117 stage.getResult(i).replaceAllUsesWith(pipelineRegister.getOut());
1119 updatePrologueAndEpilogue(group);
1125 if (!prologueGroups.empty())
1126 getState<ComponentLoweringState>().addPipelinePrologue(whileOp,
1128 if (!epilogueGroups.empty())
1129 getState<ComponentLoweringState>().addPipelineEpilogue(whileOp,
1136 calyx::RegisterOp pipelineRegister,
1138 PatternRewriter &rewriter)
const {
1140 PatternRewriter::InsertionGuard g(rewriter);
1141 rewriter.setInsertionPoint(combGroup);
1142 auto group = rewriter.create<calyx::GroupOp>(combGroup.getLoc(),
1143 combGroup.getName());
1144 rewriter.cloneRegionBefore(combGroup.getBodyRegion(),
1145 &group.getBody().front());
1146 group.getBodyRegion().back().erase();
1147 rewriter.eraseOp(combGroup);
1151 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
1152 pipelineRegister, value);
1155 for (
auto assign : group.getOps<calyx::AssignOp>())
1156 getState<ComponentLoweringState>().registerEvaluatingGroup(
1157 assign.getSrc(), group);
1163 calyx::RegisterOp pipelineRegister,
1164 PatternRewriter &rewriter)
const {
1165 auto group = cast<calyx::GroupOp>(evaluatingGroup.getOperation());
1168 auto doneOp = group.getDoneOp();
1170 cast<calyx::RegisterOp>(cast<OpResult>(doneOp.getSrc()).getOwner());
1171 auto tempIn = tempReg.getIn();
1172 auto tempWriteEn = tempReg.getWriteEn();
1175 for (
auto assign : group.getOps<calyx::AssignOp>()) {
1176 if (assign.getDest() == tempIn)
1177 assign.getDestMutable().assign(pipelineRegister.getIn());
1178 else if (assign.getDest() == tempWriteEn)
1179 assign.getDestMutable().assign(pipelineRegister.getWriteEn());
1181 doneOp.getSrcMutable().assign(pipelineRegister.getDone());
1184 if (tempReg->use_empty())
1185 rewriter.eraseOp(tempReg);
1197 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1201 PatternRewriter &rewriter)
const override {
1202 auto *entryBlock = &funcOp.getBlocks().front();
1203 rewriter.setInsertionPointToStart(
1205 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
1206 DenseSet<Block *> path;
1208 nullptr, entryBlock);
1215 const DenseSet<Block *> &path,
1216 mlir::Block *parentCtrlBlock,
1217 mlir::Block *block)
const {
1218 auto compBlockScheduleables =
1219 getState<ComponentLoweringState>().getBlockScheduleables(block);
1220 auto loc = block->front().getLoc();
1222 if (compBlockScheduleables.size() > 1) {
1223 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
1224 parentCtrlBlock = seqOp.getBodyBlock();
1227 for (
auto &group : compBlockScheduleables) {
1228 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1229 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
1230 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1231 groupPtr->getSymName());
1232 }
else if (
auto *pipeSchedPtr = std::get_if<PipelineScheduleable>(&group);
1234 auto &whileOp = pipeSchedPtr->whileOp;
1238 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
1240 rewriter.create<calyx::ParOp>(whileOp.getOperation()->getLoc());
1241 rewriter.setInsertionPointToEnd(whileBodyOp.getBodyBlock());
1244 auto bodyBlockScheduleables =
1245 getState<ComponentLoweringState>().getBlockScheduleables(
1246 whileOp.getBodyBlock());
1247 for (
auto &group : bodyBlockScheduleables)
1248 if (
auto *groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr)
1249 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1250 groupPtr->getSymName());
1252 return whileOp.getOperation()->emitError(
1253 "Unsupported block schedulable");
1256 PatternRewriter::InsertionGuard g(rewriter);
1257 rewriter.setInsertionPoint(whileCtrlOp);
1258 getState<ComponentLoweringState>().createPipelinePrologue(
1259 whileOp.getOperation(), rewriter);
1260 rewriter.setInsertionPointAfter(whileCtrlOp);
1261 getState<ComponentLoweringState>().createPipelineEpilogue(
1262 whileOp.getOperation(), rewriter);
1264 llvm_unreachable(
"Unknown scheduleable");
1275 const DenseSet<Block *> &path, Location loc,
1276 Block *from, Block *to,
1277 Block *parentCtrlBlock)
const {
1280 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1281 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
1282 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
1284 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
1285 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
1291 PatternRewriter &rewriter,
1292 mlir::Block *parentCtrlBlock,
1293 mlir::Block *preBlock,
1294 mlir::Block *block)
const {
1295 if (path.count(block) != 0)
1296 return preBlock->getTerminator()->emitError()
1297 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
1298 "'scf.for' operations.";
1300 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1301 LogicalResult bbSchedResult =
1303 if (bbSchedResult.failed())
1304 return bbSchedResult;
1307 auto successors = block->getSuccessors();
1308 auto nSuccessors = successors.size();
1309 if (nSuccessors > 0) {
1310 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
1312 if (nSuccessors > 1) {
1316 assert(nSuccessors == 2 &&
1317 "only conditional branches supported for now...");
1319 auto cond = brOp->getOperand(0);
1320 auto condGroup = getState<ComponentLoweringState>()
1321 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1322 auto symbolAttr = FlatSymbolRefAttr::get(
1323 StringAttr::get(getContext(), condGroup.getSymName()));
1325 auto ifOp = rewriter.create<calyx::IfOp>(
1326 brOp->getLoc(), cond, symbolAttr,
true);
1327 rewriter.setInsertionPointToStart(ifOp.getThenBody());
1328 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1329 rewriter.setInsertionPointToStart(ifOp.getElseBody());
1330 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1332 bool trueBrSchedSuccess =
1333 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
1334 thenSeqOp.getBodyBlock())
1336 bool falseBrSchedSuccess =
true;
1337 if (trueBrSchedSuccess) {
1338 falseBrSchedSuccess =
1339 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
1340 elseSeqOp.getBodyBlock())
1344 return success(trueBrSchedSuccess && falseBrSchedSuccess);
1347 return schedulePath(rewriter, path, brOp.getLoc(), block,
1348 successors.front(), parentCtrlBlock);
1355 SmallVector<calyx::GroupOp> initGroups,
1356 PatternRewriter &rewriter)
const {
1357 Location loc = whileOp.
getLoc();
1361 PatternRewriter::InsertionGuard g(rewriter);
1362 auto parOp = rewriter.create<calyx::ParOp>(loc);
1363 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
1364 for (calyx::GroupOp group : initGroups)
1365 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
1370 auto condGroup = getState<ComponentLoweringState>()
1371 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1372 auto symbolAttr = FlatSymbolRefAttr::get(
1373 StringAttr::get(getContext(), condGroup.getSymName()));
1374 auto whileCtrlOp = rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
1377 if (
auto bound = whileOp.
getBound()) {
1379 auto prologue = getState<ComponentLoweringState>().getPipelinePrologue(
1381 auto unrolledBound = *bound - prologue.size();
1382 whileCtrlOp->setAttr(
"bound", rewriter.getI64IntegerAttr(unrolledBound));
1392 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1395 PatternRewriter &)
const override {
1396 funcOp.walk([&](memref::LoadOp loadOp) {
1402 loadOp.getResult().replaceAllUsesWith(
1403 getState<ComponentLoweringState>()
1404 .getMemoryInterface(loadOp.getMemref())
1415 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1418 PatternRewriter &rewriter)
const override {
1419 rewriter.eraseOp(funcOp);
1425 PatternRewriter &rewriter)
const override {
1442 std::string &topLevelFunction) {
1443 if (!topLevelFunctionOpt.empty()) {
1444 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
1446 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
1447 <<
"' not found in module.";
1450 topLevelFunction = topLevelFunctionOpt;
1454 auto funcOps = moduleOp.getOps<FuncOp>();
1455 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
1456 topLevelFunction = (*funcOps.begin()).getSymName().str();
1458 moduleOp.emitError()
1459 <<
"Module contains multiple functions, but no top level "
1460 "function was set. Please see --top-level-function";
1481 using OpRewritePattern::OpRewritePattern;
1482 LogicalResult matchAndRewrite(mlir::ModuleOp,
1483 PatternRewriter &)
const override {
1488 ConversionTarget target(getContext());
1489 target.addLegalDialect<calyx::CalyxDialect>();
1490 target.addLegalDialect<scf::SCFDialect>();
1491 target.addIllegalDialect<hw::HWDialect>();
1492 target.addIllegalDialect<comb::CombDialect>();
1495 target.addIllegalOp<scf::ForOp>();
1498 target.addIllegalDialect<FuncDialect>();
1499 target.addIllegalDialect<ArithDialect>();
1500 target.addLegalOp<AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
1501 XOrIOp, OrIOp, ExtUIOp, TruncIOp, CondBranchOp, BranchOp,
1502 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp, ReturnOp,
1503 arith::ConstantOp, IndexCastOp, FuncOp, ExtSIOp>();
1505 RewritePatternSet legalizePatterns(&getContext());
1506 legalizePatterns.add<DummyPattern>(&getContext());
1507 DenseSet<Operation *> legalizedOps;
1508 if (applyPartialConversion(getOperation(), target,
1509 std::move(legalizePatterns))
1520 template <
typename TPattern,
typename... PatternArgs>
1522 PatternArgs &&...args) {
1523 RewritePatternSet ps(&getContext());
1529 template <
typename TPattern,
typename... PatternArgs>
1531 PatternArgs &&...args) {
1532 RewritePatternSet ps(&getContext());
1533 ps.add<TPattern>(&getContext(), args...);
1540 "Should only apply 1 partial lowering pattern at once");
1546 GreedyRewriteConfig config;
1547 config.enableRegionSimplification =
1548 mlir::GreedySimplifyRegionLevel::Disabled;
1550 config.maxIterations = 1;
1555 (void)applyPatternsAndFoldGreedily(getOperation(), std::move(
pattern),
1570 std::string topLevelFunction;
1572 signalPassFailure();
1578 signalPassFailure();
1581 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
1592 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
1593 SmallVector<LoweringPattern, 8> loweringPatterns;
1597 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
1601 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
1605 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
1609 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
1615 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
1619 addOncePattern<BuildPipelineRegs>(loweringPatterns, patternState, funcMap,
1629 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
1633 addOncePattern<BuildPipelineGroups>(loweringPatterns, patternState, funcMap,
1639 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
1644 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
1647 addGreedyPattern<calyx::DeduplicateParallelOp>(loweringPatterns);
1648 addGreedyPattern<calyx::DeduplicateStaticParallelOp>(loweringPatterns);
1652 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
1658 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
1662 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
1667 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
1671 for (
auto &pat : loweringPatterns) {
1677 signalPassFailure();
1684 RewritePatternSet cleanupPatterns(&getContext());
1687 if (failed(applyPatternsAndFoldGreedily(getOperation(),
1688 std::move(cleanupPatterns)))) {
1689 signalPassFailure();
1693 if (ciderSourceLocationMetadata) {
1696 SmallVector<Attribute, 16> sourceLocations;
1697 getOperation()->walk([&](calyx::ComponentOp component) {
1698 return getCiderSourceLocationMetadata(component, sourceLocations);
1701 MLIRContext *context = getOperation()->getContext();
1702 getOperation()->setAttr(
"calyx.metadata",
1703 ArrayAttr::get(context, sourceLocations));
1714 return std::make_unique<pipelinetocalyx::LoopScheduleToCalyxPass>();
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
RewritePatternSet pattern
std::string blockName(Block *b)
Returns a meaningful name for a block within the program scope (removes the ^ prefix from block names...
T * getState(calyx::ComponentOp op)
Returns the component lowering state associated with op.
void setFuncOpResultMapping(const DenseMap< unsigned, unsigned > &mapping)
Assign a mapping between the source funcOp result indices and the corresponding output port indices o...
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.
ComponentLoweringStateInterface(calyx::ComponentOp component)
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.
DenseMap< mlir::func::FuncOp, calyx::ComponentOp > & functionMapping
CalyxLoweringState & loweringState() const
Return the calyx lowering state for this pattern.
Holds common utilities used for scheduling when lowering to Calyx.
LoopSchedulePipelineOp getOperation()
WhileOpInterface(LoopSchedulePipelineOp op)
Location getLoc() override
Builds a control schedule by traversing the CFG of the function and associating this with the previou...
LogicalResult buildCFGControl(DenseSet< Block * > path, PatternRewriter &rewriter, mlir::Block *parentCtrlBlock, mlir::Block *preBlock, mlir::Block *block) const
LogicalResult schedulePath(PatternRewriter &rewriter, const DenseSet< Block * > &path, Location loc, Block *from, Block *to, Block *parentCtrlBlock) const
Schedules a block by inserting a branch argument assignment block (if any) before recursing into the ...
LogicalResult scheduleBasicBlock(PatternRewriter &rewriter, const DenseSet< Block * > &path, mlir::Block *parentCtrlBlock, mlir::Block *block) const
Sequentially schedules the groups that registered themselves with 'block'.
calyx::WhileOp buildWhileCtrlOp(PipelineWhileOp whileOp, SmallVector< calyx::GroupOp > initGroups, PatternRewriter &rewriter) const
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
Iterate through the operations of a source function and instantiate components or primitives based on...
LogicalResult buildLibraryOp(PatternRewriter &rewriter, TSrcOp op) const
buildLibraryOp which provides in- and output types based on the operands and results of the op argume...
void assignAddressPorts(PatternRewriter &rewriter, Location loc, calyx::GroupInterface group, calyx::MemoryInterface memoryInterface, Operation::operand_range addressValues) const
Creates assignments within the provided group to the address ports of the memoryOp based on the provi...
LogicalResult buildLibraryOp(PatternRewriter &rewriter, TSrcOp op, TypeRange srcTypes, TypeRange dstTypes) const
buildLibraryOp will build a TCalyxLibOp inside a TGroupOp based on the source operation TSrcOp.
LogicalResult buildLibraryBinaryPipeOp(PatternRewriter &rewriter, TSrcOp op, TOpType opPipe, Value out) const
buildLibraryBinaryPipeOp will build a TCalyxLibBinaryPipeOp, to deal with MulIOp, DivUIOp and RemUIOp...
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
TGroupOp createGroupForOp(PatternRewriter &rewriter, Operation *op) const
Creates a group named by the basic block which the input op resides in.
LogicalResult buildOp(PatternRewriter &rewriter, BranchOpInterface brOp) const
Op builder specializations.
Builds groups for assigning registers for pipeline stages.
calyx::GroupOp replaceGroupRegister(calyx::GroupInterface evaluatingGroup, calyx::RegisterOp pipelineRegister, PatternRewriter &rewriter) const
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult buildStageGroups(LoopSchedulePipelineOp whileOp, LoopSchedulePipelineStageOp stage, PatternRewriter &rewriter) const
calyx::GroupOp convertCombToSeqGroup(calyx::CombGroupOp combGroup, calyx::RegisterOp pipelineRegister, Value value, PatternRewriter &rewriter) const
Builds registers for each pipeline stage in the program.
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
In BuildWhileGroups, a register is created for each iteration argumenet of the while op.
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
Erases FuncOp operations.
LogicalResult matchAndRewrite(FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
Handles the current state of lowering of a Calyx component.
ComponentLoweringState(calyx::ComponentOp component)
LateSSAReplacement contains various functions for replacing SSA values that were not replaced during ...
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &) const override
LogicalResult partialPatternRes
void addOncePattern(SmallVectorImpl< LoweringPattern > &patterns, PatternArgs &&...args)
'Once' patterns are expected to take an additional LogicalResult& argument, to forward their result s...
LoopScheduleToCalyxPass()
LogicalResult labelEntryPoint(StringRef topLevelFunction)
Labels the entry point of a Calyx program.
void addGreedyPattern(SmallVectorImpl< LoweringPattern > &patterns, PatternArgs &&...args)
std::shared_ptr< calyx::CalyxLoweringState > loweringState
LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp, std::string &topLevelFunction)
void runOnOperation() override
LogicalResult runPartialPattern(RewritePatternSet &pattern, bool runOnce)
Holds additional information required for scheduling Pipeline pipelines.
void createPipelinePrologue(Operation *op, PatternRewriter &rewriter)
Create the pipeline prologue.
std::optional< calyx::RegisterOp > getPipelineRegister(Value value)
Returns the pipeline register for this value if its defining operation is a stage,...
std::optional< TGroupOp > getNonPipelinedGroupFrom(Operation *op)
Returns the group registered for this non-pipelined value, and None otherwise.
SmallVector< SmallVector< StringAttr > > getPipelinePrologue(Operation *op)
Get the pipeline prologue.
void addPipelineReg(Operation *stage, calyx::RegisterOp reg, unsigned idx)
Register reg as being the idx'th pipeline register for the stage.
void addPipelineEpilogue(Operation *op, SmallVector< StringAttr > groupNames)
Add a stage's groups to the pipeline epilogue.
DenseMap< Operation *, calyx::GroupInterface > operationToGroup
A mapping between operations and the group to which it was assigned.
void createPipelineEpilogue(Operation *op, PatternRewriter &rewriter)
Create the pipeline epilogue.
void addPipelinePrologue(Operation *op, SmallVector< StringAttr > groupNames)
Add a stage's groups to the pipeline prologue.
void registerNonPipelineOperations(Operation *op, calyx::GroupInterface group)
Registers operations that may be used in a pipeline, but does not produce a value to be used in a fur...
DenseMap< Operation *, SmallVector< SmallVector< StringAttr > > > pipelineEpilogue
A mapping from pipeline ops to a vector of vectors of group names that constitute the pipeline epilog...
const DenseMap< unsigned, calyx::RegisterOp > & getPipelineRegs(Operation *stage)
Return a mapping of stage result indices to pipeline registers.
DenseMap< Operation *, SmallVector< SmallVector< StringAttr > > > pipelinePrologue
A mapping from pipeline ops to a vector of vectors of group names that constitute the pipeline prolog...
DenseMap< Operation *, DenseMap< unsigned, calyx::RegisterOp > > pipelineRegs
A mapping from pipeline stages to their registers.
Block * getConditionBlock() override
Block::BlockArgListType getBodyArgs() override
Block * getBodyBlock() override
Value getConditionValue() override
std::optional< int64_t > getBound() override
PipelineWhileOp(LoopSchedulePipelineOp op)
void addMandatoryComponentPorts(PatternRewriter &rewriter, SmallVectorImpl< calyx::PortInfo > &ports)
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 normalizeType(OpBuilder &builder, Type type)
LogicalResult applyModuleOpConversion(mlir::ModuleOp, StringRef topLevelFunction)
Helper to update the top-level ModuleOp to set the entrypoing function.
bool matchConstantOp(Operation *op, APInt &value)
unsigned handleZeroWidth(int64_t dim)
bool noStoresToMemory(Value memoryReference)
bool singleLoadFromMemory(Value memoryReference)
static LogicalResult buildAllocOp(ComponentLoweringState &componentState, PatternRewriter &rewriter, TAllocOp allocOp)
std::variant< calyx::GroupOp, PipelineScheduleable > Scheduleable
A variant of types representing scheduleable operations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< OperationPass< ModuleOp > > createLoopScheduleToCalyxPass()
Create a LoopSchedule to Calyx conversion pass.
std::optional< Value > done
std::optional< Value > writeEn
std::optional< Value > writeData
std::optional< Value > readData
SmallVector< Value > addrPorts
When building groups which contain accesses to multiple sequential components, a group_done op is cre...
GroupDoneOp's are terminator operations and should therefore be the last operator in a group.
This holds information about the port for either a Component or Cell.
Creates a new Calyx component for each FuncOp in the program.
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
RewritePatternSet pattern
SmallVector< calyx::GroupOp > initGroups
The group(s) to schedule before the while operation These groups should set the initial value(s) of t...
PipelineWhileOp whileOp
While operation to schedule.