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"
35 #define GEN_PASS_DEF_LOOPSCHEDULETOCALYX
36 #include "circt/Conversion/Passes.h.inc"
41 using namespace mlir::arith;
42 using namespace mlir::cf;
44 using namespace circt::loopschedule;
47 namespace pipelinetocalyx {
56 : calyx::WhileOpInterface<LoopSchedulePipelineOp>(op) {}
59 return getOperation().getStagesBlock().getArguments();
62 Block *
getBodyBlock()
override {
return &getOperation().getStagesBlock(); }
67 return getOperation().getCondBlock().getTerminator()->getOperand(0);
71 return getOperation().getTripCount();
88 using Scheduleable = std::variant<calyx::GroupOp, PipelineScheduleable>;
96 calyx::GroupInterface group) {
97 operationToGroup[op] = group;
102 template <
typename TGroupOp = calyx::GroupInterface>
104 auto it = operationToGroup.find(op);
105 if (it == operationToGroup.end())
108 if constexpr (std::is_same<TGroupOp, calyx::GroupInterface>::value)
111 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
112 assert(group &&
"Actual group type differed from expected group type");
118 assert(pipelineRegs[stage].count(idx) == 0);
119 assert(idx < stage->getNumResults());
120 pipelineRegs[stage][idx] =
reg;
124 const DenseMap<unsigned, calyx::RegisterOp> &
126 return pipelineRegs[stage];
131 pipelinePrologue[op].push_back(groupNames);
136 pipelineEpilogue[op].push_back(groupNames);
141 return pipelinePrologue[op];
146 auto stages = pipelinePrologue[op];
147 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
148 PatternRewriter::InsertionGuard g(rewriter);
149 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
150 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
151 for (
size_t j = 0; j < i + 1; ++j)
152 for (
auto group : stages[j])
153 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
159 auto stages = pipelineEpilogue[op];
160 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
161 PatternRewriter::InsertionGuard g(rewriter);
162 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
163 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
164 for (
size_t j = i, f = stages.size(); j < f; ++j)
165 for (
auto group : stages[j])
166 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
177 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
pipelineRegs;
199 : calyx::ComponentLoweringStateInterface(component) {}
209 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
213 PatternRewriter &rewriter)
const override {
216 bool opBuiltSuccessfully =
true;
217 funcOp.walk([&](Operation *_op) {
218 opBuiltSuccessfully &=
219 TypeSwitch<mlir::Operation *, bool>(_op)
220 .template Case<arith::ConstantOp, ReturnOp, BranchOpInterface,
222 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
225 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp,
226 AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp, MulIOp,
227 DivUIOp, RemUIOp, IndexCastOp,
229 LoopScheduleTerminatorOp>(
230 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
231 .
template Case<FuncOp, LoopSchedulePipelineOp,
232 LoopScheduleRegisterOp,
233 LoopSchedulePipelineStageOp>([&](
auto) {
237 .Default([&](
auto op) {
238 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
242 return opBuiltSuccessfully ? WalkResult::advance()
243 : WalkResult::interrupt();
246 return success(opBuiltSuccessfully);
251 LogicalResult buildOp(PatternRewriter &rewriter,
252 BranchOpInterface brOp)
const;
253 LogicalResult buildOp(PatternRewriter &rewriter,
254 arith::ConstantOp constOp)
const;
255 LogicalResult buildOp(PatternRewriter &rewriter, AddIOp op)
const;
256 LogicalResult buildOp(PatternRewriter &rewriter, SubIOp op)
const;
257 LogicalResult buildOp(PatternRewriter &rewriter, MulIOp op)
const;
258 LogicalResult buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
259 LogicalResult buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
260 LogicalResult buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
261 LogicalResult buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
262 LogicalResult buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
263 LogicalResult buildOp(PatternRewriter &rewriter, AndIOp op)
const;
264 LogicalResult buildOp(PatternRewriter &rewriter, OrIOp op)
const;
265 LogicalResult buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
266 LogicalResult buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
267 LogicalResult buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
268 LogicalResult buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
269 LogicalResult buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
270 LogicalResult buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
271 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
272 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
273 LogicalResult buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
274 LogicalResult buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
275 LogicalResult buildOp(PatternRewriter &rewriter,
276 LoopScheduleTerminatorOp op)
const;
280 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
282 TypeRange srcTypes, TypeRange dstTypes)
const {
283 SmallVector<Type> types;
284 llvm::append_range(types, srcTypes);
285 llvm::append_range(types, dstTypes);
288 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
289 rewriter, op.getLoc(), types);
291 auto directions = calyxOp.portDirections();
292 SmallVector<Value, 4> opInputPorts;
293 SmallVector<Value, 4> opOutputPorts;
294 for (
auto dir : enumerate(directions)) {
296 opInputPorts.push_back(calyxOp.getResult(dir.index()));
298 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
301 opInputPorts.size() == op->getNumOperands() &&
302 opOutputPorts.size() == op->getNumResults() &&
303 "Expected an equal number of in/out ports in the Calyx library op with "
304 "respect to the number of operands/results of the source operation.");
307 auto group = createGroupForOp<TGroupOp>(rewriter, op);
308 rewriter.setInsertionPointToEnd(group.getBodyBlock());
309 for (
auto dstOp : enumerate(opInputPorts))
310 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(),
311 op->getOperand(dstOp.index()));
314 for (
auto res : enumerate(opOutputPorts)) {
315 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
317 op->getResult(res.index()).replaceAllUsesWith(res.value());
324 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
326 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
327 rewriter, op, op.getOperandTypes(), op->getResultTypes());
331 template <
typename TGroupOp>
333 Block *block = op->getBlock();
334 auto groupName = getState<ComponentLoweringState>().getUniqueName(
336 return calyx::createGroup<TGroupOp>(
337 rewriter, getState<ComponentLoweringState>().getComponentOp(),
338 op->getLoc(), groupName);
343 template <
typename TOpType,
typename TSrcOp>
345 TOpType opPipe, Value out)
const {
346 StringRef opName = TSrcOp::getOperationName().split(
".").second;
347 Location loc = op.getLoc();
348 Type
width = op.getResult().getType();
350 op.getResult().replaceAllUsesWith(out);
352 op.getLoc(), rewriter, getComponent(),
width.getIntOrFloatBitWidth(),
353 getState<ComponentLoweringState>().getUniqueName(opName));
355 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
356 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
359 rewriter.setInsertionPointToEnd(group.getBodyBlock());
360 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
361 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
363 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), out);
365 rewriter.create<calyx::AssignOp>(loc,
reg.getWriteEn(), opPipe.getDone());
366 rewriter.create<calyx::AssignOp>(
370 rewriter.create<calyx::GroupDoneOp>(loc,
reg.getDone());
373 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
374 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
376 getState<ComponentLoweringState>().registerEvaluatingGroup(
377 opPipe.getRight(), group);
385 calyx::GroupInterface group,
387 Operation::operand_range addressValues)
const {
388 IRRewriter::InsertionGuard guard(rewriter);
389 rewriter.setInsertionPointToEnd(group.getBody());
390 auto addrPorts = memoryInterface.
addrPorts();
391 if (addressValues.empty()) {
393 addrPorts.size() == 1 &&
394 "We expected a 1 dimensional memory of size 1 because there were no "
395 "address assignment values");
397 rewriter.create<calyx::AssignOp>(
401 assert(addrPorts.size() == addressValues.size() &&
402 "Mismatch between number of address ports of the provided memory "
403 "and address assignment values");
404 for (
auto address : enumerate(addressValues))
405 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
411 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
412 memref::LoadOp loadOp)
const {
413 Value memref = loadOp.getMemref();
414 auto memoryInterface =
415 getState<ComponentLoweringState>().getMemoryInterface(memref);
423 auto combGroup = createGroupForOp<calyx::CombGroupOp>(rewriter, loadOp);
424 assignAddressPorts(rewriter, loadOp.getLoc(), combGroup, memoryInterface,
425 loadOp.getIndices());
436 getState<ComponentLoweringState>().registerEvaluatingGroup(
437 loadOp.getResult(), combGroup);
439 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
440 assignAddressPorts(rewriter, loadOp.getLoc(), group, memoryInterface,
441 loadOp.getIndices());
452 loadOp.getLoc(), rewriter, getComponent(),
453 loadOp.getMemRefType().getElementTypeBitWidth(),
454 getState<ComponentLoweringState>().getUniqueName(
"load"));
456 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
457 reg, memoryInterface.readData());
458 loadOp.getResult().replaceAllUsesWith(
reg.getOut());
459 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
465 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
466 memref::StoreOp storeOp)
const {
467 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
468 storeOp.getMemref());
469 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
473 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
475 assignAddressPorts(rewriter, storeOp.getLoc(), group, memoryInterface,
476 storeOp.getIndices());
477 rewriter.setInsertionPointToEnd(group.getBodyBlock());
478 rewriter.create<calyx::AssignOp>(
479 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
480 rewriter.create<calyx::AssignOp>(
481 storeOp.getLoc(), memoryInterface.writeEn(),
482 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
483 if (memoryInterface.contentEnOpt().has_value()) {
485 rewriter.create<calyx::AssignOp>(
486 storeOp.getLoc(), memoryInterface.contentEn(),
487 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
489 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
491 getState<ComponentLoweringState>().registerNonPipelineOperations(storeOp,
497 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
499 Location loc = mul.getLoc();
500 Type
width = mul.getResult().getType(), one = rewriter.getI1Type();
502 getState<ComponentLoweringState>()
503 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
505 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
506 rewriter, mul, mulPipe,
510 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
512 Location loc = div.getLoc();
513 Type
width = div.getResult().getType(), one = rewriter.getI1Type();
515 getState<ComponentLoweringState>()
516 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
518 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
519 rewriter, div, divPipe,
523 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
525 Location loc = rem.getLoc();
526 Type
width = rem.getResult().getType(), one = rewriter.getI1Type();
528 getState<ComponentLoweringState>()
529 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
531 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
532 rewriter, rem, remPipe,
536 template <
typename TAllocOp>
538 PatternRewriter &rewriter, TAllocOp allocOp) {
539 rewriter.setInsertionPointToStart(
541 MemRefType memtype = allocOp.getType();
542 SmallVector<int64_t> addrSizes;
543 SmallVector<int64_t> sizes;
544 for (int64_t dim : memtype.getShape()) {
545 sizes.push_back(dim);
550 if (sizes.empty() && addrSizes.empty()) {
552 addrSizes.push_back(1);
554 auto memoryOp = rewriter.create<calyx::MemoryOp>(
556 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
559 memoryOp->setAttr(
"external",
566 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
567 memref::AllocOp allocOp)
const {
568 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
571 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
572 memref::AllocaOp allocOp)
const {
573 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
576 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
577 LoopScheduleTerminatorOp term)
const {
578 if (term.getOperands().size() == 0)
582 auto *pipeline = term->getParentOp();
583 for (
size_t i = 0, e = pipeline->getNumResults(); i < e; ++i)
584 pipeline->getResult(i).replaceAllUsesWith(term.getResults()[i]);
589 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
590 BranchOpInterface brOp)
const {
595 Block *srcBlock = brOp->getBlock();
596 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
597 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
598 if (succOperands.empty())
601 std::string groupName =
loweringState().blockName(srcBlock) +
"_to_" +
603 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
604 brOp.getLoc(), groupName);
606 auto dstBlockArgRegs =
607 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
609 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
610 auto reg = dstBlockArgRegs[arg.index()];
613 getState<ComponentLoweringState>().getComponentOp(),
reg,
618 getState<ComponentLoweringState>().addBlockArgGroup(
619 srcBlock, succBlock.value(), groupOp);
626 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
627 ReturnOp retOp)
const {
628 if (retOp.getNumOperands() == 0)
631 std::string groupName =
632 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
633 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
634 retOp.getLoc(), groupName);
635 for (
auto op : enumerate(retOp.getOperands())) {
636 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
638 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
642 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
647 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
648 arith::ConstantOp constOp)
const {
652 auto hwConstOp = rewriter.replaceOpWithNewOp<
hw::ConstantOp>(constOp, value);
653 hwConstOp->moveAfter(getComponent().getBodyBlock(),
654 getComponent().getBodyBlock()->begin());
658 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
660 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
662 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
664 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
666 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
668 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
670 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
672 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
674 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
676 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
678 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
680 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
682 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
684 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
686 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
688 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
691 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
693 switch (op.getPredicate()) {
694 case CmpIPredicate::eq:
695 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
696 case CmpIPredicate::ne:
697 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
698 case CmpIPredicate::uge:
699 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
700 case CmpIPredicate::ult:
701 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
702 case CmpIPredicate::ugt:
703 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
704 case CmpIPredicate::ule:
705 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
706 case CmpIPredicate::sge:
707 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
708 case CmpIPredicate::slt:
709 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
710 case CmpIPredicate::sgt:
711 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
712 case CmpIPredicate::sle:
713 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
715 llvm_unreachable(
"unsupported comparison predicate");
717 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
719 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
720 rewriter, op, {op.getOperand().getType()}, {op.getType()});
722 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
724 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
725 rewriter, op, {op.getOperand().getType()}, {op.getType()});
728 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
729 IndexCastOp op)
const {
732 unsigned targetBits = targetType.getIntOrFloatBitWidth();
733 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
734 LogicalResult res = success();
736 if (targetBits == sourceBits) {
739 op.getResult().replaceAllUsesWith(op.getOperand());
742 if (sourceBits > targetBits)
743 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
744 rewriter, op, {sourceType}, {targetType});
746 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
747 rewriter, op, {sourceType}, {targetType});
749 rewriter.eraseOp(op);
755 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
759 PatternRewriter &rewriter)
const override {
762 DenseMap<Value, unsigned> funcOpArgRewrites;
766 DenseMap<unsigned, unsigned> funcOpResultMapping;
774 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
778 SmallVector<calyx::PortInfo> inPorts, outPorts;
779 FunctionType funcType = funcOp.getFunctionType();
780 unsigned extMemCounter = 0;
781 for (
auto arg : enumerate(funcOp.getArguments())) {
782 if (isa<MemRefType>(arg.value().getType())) {
785 "ext_mem" + std::to_string(extMemoryCompPortIndices.size());
786 extMemoryCompPortIndices[arg.value()] = {inPorts.size(),
789 extMemCounter++, inPorts, outPorts);
792 auto inName =
"in" + std::to_string(arg.index());
793 funcOpArgRewrites[arg.value()] = inPorts.size();
795 rewriter.getStringAttr(inName),
801 for (
auto res : enumerate(funcType.getResults())) {
802 funcOpResultMapping[res.index()] = outPorts.size();
804 rewriter.getStringAttr(
"out" + std::to_string(res.index())),
811 auto ports = inPorts;
812 llvm::append_range(ports, outPorts);
816 auto compOp = rewriter.create<calyx::ComponentOp>(
817 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
820 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
823 functionMapping[funcOp] = compOp;
828 for (
auto &mapping : funcOpArgRewrites)
829 mapping.getFirst().replaceAllUsesWith(
830 compOp.getArgument(mapping.getSecond()));
833 for (
auto extMemPortIndices : extMemoryCompPortIndices) {
837 unsigned inPortsIt = extMemPortIndices.getSecond().first;
838 unsigned outPortsIt = extMemPortIndices.getSecond().second +
839 compOp.getInputPortInfo().size();
840 extMemPorts.
readData = compOp.getArgument(inPortsIt++);
841 extMemPorts.
done = compOp.getArgument(inPortsIt);
842 extMemPorts.
writeData = compOp.getArgument(outPortsIt++);
843 unsigned nAddresses =
844 cast<MemRefType>(extMemPortIndices.getFirst().getType())
847 for (
unsigned j = 0; j < nAddresses; ++j)
848 extMemPorts.
addrPorts.push_back(compOp.getArgument(outPortsIt++));
849 extMemPorts.
writeEn = compOp.getArgument(outPortsIt);
853 compState->registerMemoryInterface(extMemPortIndices.getFirst(),
866 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
870 PatternRewriter &rewriter)
const override {
871 LogicalResult res = success();
872 funcOp.walk([&](Operation *op) {
873 if (!isa<LoopSchedulePipelineOp>(op))
874 return WalkResult::advance();
878 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
886 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
887 std::string name = getState<ComponentLoweringState>()
890 "_arg" + std::to_string(arg.index());
893 arg.value().getType().getIntOrFloatBitWidth(), name);
894 getState<ComponentLoweringState>().addLoopIterReg(whileOp,
reg,
896 arg.value().replaceAllUsesWith(
reg.getOut());
900 ->getArgument(arg.index())
901 .replaceAllUsesWith(
reg.getOut());
905 SmallVector<calyx::GroupOp> initGroups;
906 auto numOperands = whileOp.
getOperation()->getNumOperands();
907 for (
size_t i = 0; i < numOperands; ++i) {
909 getState<ComponentLoweringState>().buildLoopIterArgAssignments(
911 getState<ComponentLoweringState>().getComponentOp(),
912 getState<ComponentLoweringState>().getUniqueName(
914 "_init_" + std::to_string(i),
916 initGroups.push_back(initGroupOp);
921 getState<ComponentLoweringState>().addBlockScheduleable(
926 return WalkResult::advance();
934 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
938 PatternRewriter &rewriter)
const override {
939 funcOp.walk([&](LoopScheduleRegisterOp op) {
941 auto *parent = op->getParentOp();
942 auto stage = dyn_cast<LoopSchedulePipelineStageOp>(parent);
947 for (
auto &operand : op->getOpOperands()) {
948 unsigned i = operand.getOperandNumber();
951 Value stageResult = stage.getResult(i);
952 bool isIterArg =
false;
953 for (
auto &use : stageResult.getUses()) {
954 if (
auto term = dyn_cast<LoopScheduleTerminatorOp>(use.getOwner())) {
955 if (use.getOperandNumber() < term.getIterArgs().size()) {
957 dyn_cast<LoopSchedulePipelineOp>(stage->getParentOp()));
958 auto reg = getState<ComponentLoweringState>().getLoopIterReg(
959 whileOp, use.getOperandNumber());
960 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
969 Value value = operand.get();
970 Type resultType = value.getType();
971 assert(isa<IntegerType>(resultType) &&
972 "unsupported pipeline result type");
973 auto name = SmallString<20>(
"stage_");
974 name += std::to_string(stage.getStageNumber());
975 name +=
"_register_";
976 name += std::to_string(i);
977 unsigned width = resultType.getIntOrFloatBitWidth();
980 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
994 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
998 PatternRewriter &rewriter)
const override {
999 for (
auto pipeline : funcOp.getOps<LoopSchedulePipelineOp>())
1001 pipeline.getStagesBlock().getOps<LoopSchedulePipelineStageOp>())
1002 if (failed(buildStageGroups(pipeline, stage, rewriter)))
1009 LoopSchedulePipelineStageOp stage,
1010 PatternRewriter &rewriter)
const {
1012 auto pipelineRegisters =
1013 getState<ComponentLoweringState>().getPipelineRegs(stage);
1017 size_t numStages = whileOp.getStagesBlock().getOperations().size() - 1;
1021 SmallVector<StringAttr> prologueGroups, epilogueGroups;
1023 auto updatePrologueAndEpilogue = [&](calyx::GroupOp group) {
1025 getState<ComponentLoweringState>().addBlockScheduleable(stage->getBlock(),
1034 unsigned stageNumber = stage.getStageNumber();
1035 if (stageNumber < numStages - 1)
1036 prologueGroups.push_back(group.getSymNameAttr());
1037 if (stageNumber > 0)
1038 epilogueGroups.push_back(group.getSymNameAttr());
1041 MutableArrayRef<OpOperand> operands =
1042 stage.getBodyBlock().getTerminator()->getOpOperands();
1043 bool isStageWithNoPipelinedValues =
1044 operands.empty() && !stage.getBodyBlock().empty();
1045 if (isStageWithNoPipelinedValues) {
1048 for (
auto &op : stage.getBodyBlock())
1049 if (
auto group = getState<ComponentLoweringState>()
1050 .getNonPipelinedGroupFrom<calyx::GroupOp>(&op))
1051 updatePrologueAndEpilogue(*group);
1054 for (
auto &operand : operands) {
1055 unsigned i = operand.getOperandNumber();
1056 Value value = operand.get();
1059 auto pipelineRegister = pipelineRegisters[i];
1062 calyx::GroupInterface evaluatingGroup =
1063 getState<ComponentLoweringState>().getEvaluatingGroup(value);
1066 calyx::GroupOp group;
1070 if (
auto combGroup =
1071 dyn_cast<calyx::CombGroupOp>(evaluatingGroup.getOperation()))
1073 convertCombToSeqGroup(combGroup, pipelineRegister, value, rewriter);
1076 replaceGroupRegister(evaluatingGroup, pipelineRegister, rewriter);
1079 stage.getResult(i).replaceAllUsesWith(pipelineRegister.getOut());
1081 updatePrologueAndEpilogue(group);
1087 if (!prologueGroups.empty())
1088 getState<ComponentLoweringState>().addPipelinePrologue(whileOp,
1090 if (!epilogueGroups.empty())
1091 getState<ComponentLoweringState>().addPipelineEpilogue(whileOp,
1098 calyx::RegisterOp pipelineRegister,
1100 PatternRewriter &rewriter)
const {
1102 PatternRewriter::InsertionGuard g(rewriter);
1103 rewriter.setInsertionPoint(combGroup);
1104 auto group = rewriter.create<calyx::GroupOp>(combGroup.getLoc(),
1105 combGroup.getName());
1106 rewriter.cloneRegionBefore(combGroup.getBodyRegion(),
1107 &group.getBody().front());
1108 group.getBodyRegion().back().erase();
1109 rewriter.eraseOp(combGroup);
1113 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
1114 pipelineRegister, value);
1117 for (
auto assign : group.getOps<calyx::AssignOp>())
1118 getState<ComponentLoweringState>().registerEvaluatingGroup(
1119 assign.getSrc(), group);
1125 calyx::RegisterOp pipelineRegister,
1126 PatternRewriter &rewriter)
const {
1127 auto group = cast<calyx::GroupOp>(evaluatingGroup.getOperation());
1130 auto doneOp = group.getDoneOp();
1132 cast<calyx::RegisterOp>(cast<OpResult>(doneOp.getSrc()).getOwner());
1133 auto tempIn = tempReg.getIn();
1134 auto tempWriteEn = tempReg.getWriteEn();
1137 for (
auto assign : group.getOps<calyx::AssignOp>()) {
1138 if (assign.getDest() == tempIn)
1139 assign.getDestMutable().assign(pipelineRegister.getIn());
1140 else if (assign.getDest() == tempWriteEn)
1141 assign.getDestMutable().assign(pipelineRegister.getWriteEn());
1143 doneOp.getSrcMutable().assign(pipelineRegister.getDone());
1146 rewriter.eraseOp(tempReg);
1158 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1162 PatternRewriter &rewriter)
const override {
1163 auto *entryBlock = &funcOp.getBlocks().front();
1164 rewriter.setInsertionPointToStart(
1166 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
1167 DenseSet<Block *> path;
1168 return buildCFGControl(path, rewriter, topLevelSeqOp.getBodyBlock(),
1169 nullptr, entryBlock);
1176 const DenseSet<Block *> &path,
1177 mlir::Block *parentCtrlBlock,
1178 mlir::Block *block)
const {
1179 auto compBlockScheduleables =
1180 getState<ComponentLoweringState>().getBlockScheduleables(block);
1181 auto loc = block->front().getLoc();
1183 if (compBlockScheduleables.size() > 1) {
1184 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
1185 parentCtrlBlock = seqOp.getBodyBlock();
1188 for (
auto &group : compBlockScheduleables) {
1189 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1190 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
1191 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1192 groupPtr->getSymName());
1193 }
else if (
auto *pipeSchedPtr = std::get_if<PipelineScheduleable>(&group);
1195 auto &whileOp = pipeSchedPtr->whileOp;
1198 buildWhileCtrlOp(whileOp, pipeSchedPtr->initGroups, rewriter);
1199 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
1201 rewriter.create<calyx::ParOp>(whileOp.getOperation()->getLoc());
1202 rewriter.setInsertionPointToEnd(whileBodyOp.getBodyBlock());
1205 auto bodyBlockScheduleables =
1206 getState<ComponentLoweringState>().getBlockScheduleables(
1207 whileOp.getBodyBlock());
1208 for (
auto &group : bodyBlockScheduleables)
1209 if (
auto *groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr)
1210 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1211 groupPtr->getSymName());
1213 return whileOp.getOperation()->emitError(
1214 "Unsupported block schedulable");
1217 PatternRewriter::InsertionGuard g(rewriter);
1218 rewriter.setInsertionPoint(whileCtrlOp);
1219 getState<ComponentLoweringState>().createPipelinePrologue(
1220 whileOp.getOperation(), rewriter);
1221 rewriter.setInsertionPointAfter(whileCtrlOp);
1222 getState<ComponentLoweringState>().createPipelineEpilogue(
1223 whileOp.getOperation(), rewriter);
1225 llvm_unreachable(
"Unknown scheduleable");
1236 const DenseSet<Block *> &path, Location loc,
1237 Block *from, Block *to,
1238 Block *parentCtrlBlock)
const {
1241 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1242 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
1243 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
1245 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
1246 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
1248 return buildCFGControl(path, rewriter, parentCtrlBlock, from, to);
1252 PatternRewriter &rewriter,
1253 mlir::Block *parentCtrlBlock,
1254 mlir::Block *preBlock,
1255 mlir::Block *block)
const {
1256 if (path.count(block) != 0)
1257 return preBlock->getTerminator()->emitError()
1258 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
1259 "'scf.for' operations.";
1261 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1262 LogicalResult bbSchedResult =
1263 scheduleBasicBlock(rewriter, path, parentCtrlBlock, block);
1264 if (bbSchedResult.failed())
1265 return bbSchedResult;
1268 auto successors = block->getSuccessors();
1269 auto nSuccessors = successors.size();
1270 if (nSuccessors > 0) {
1271 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
1273 if (nSuccessors > 1) {
1277 assert(nSuccessors == 2 &&
1278 "only conditional branches supported for now...");
1280 auto cond = brOp->getOperand(0);
1281 auto condGroup = getState<ComponentLoweringState>()
1282 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1286 auto ifOp = rewriter.create<calyx::IfOp>(
1287 brOp->getLoc(), cond, symbolAttr,
true);
1288 rewriter.setInsertionPointToStart(ifOp.getThenBody());
1289 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1290 rewriter.setInsertionPointToStart(ifOp.getElseBody());
1291 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1293 bool trueBrSchedSuccess =
1294 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
1295 thenSeqOp.getBodyBlock())
1297 bool falseBrSchedSuccess =
true;
1298 if (trueBrSchedSuccess) {
1299 falseBrSchedSuccess =
1300 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
1301 elseSeqOp.getBodyBlock())
1305 return success(trueBrSchedSuccess && falseBrSchedSuccess);
1308 return schedulePath(rewriter, path, brOp.getLoc(), block,
1309 successors.front(), parentCtrlBlock);
1316 SmallVector<calyx::GroupOp> initGroups,
1317 PatternRewriter &rewriter)
const {
1318 Location loc = whileOp.
getLoc();
1322 PatternRewriter::InsertionGuard g(rewriter);
1323 auto parOp = rewriter.create<calyx::ParOp>(loc);
1324 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
1325 for (calyx::GroupOp group : initGroups)
1326 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
1331 auto condGroup = getState<ComponentLoweringState>()
1332 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1335 auto whileCtrlOp = rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
1338 if (
auto bound = whileOp.
getBound()) {
1340 auto prologue = getState<ComponentLoweringState>().getPipelinePrologue(
1342 auto unrolledBound = *bound - prologue.size();
1343 whileCtrlOp->setAttr(
"bound", rewriter.getI64IntegerAttr(unrolledBound));
1353 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1356 PatternRewriter &)
const override {
1357 funcOp.walk([&](memref::LoadOp loadOp) {
1363 loadOp.getResult().replaceAllUsesWith(
1364 getState<ComponentLoweringState>()
1365 .getMemoryInterface(loadOp.getMemref())
1376 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1379 PatternRewriter &rewriter)
const override {
1380 rewriter.eraseOp(funcOp);
1386 PatternRewriter &rewriter)
const override {
1400 void runOnOperation()
override;
1403 std::string &topLevelFunction) {
1404 if (!topLevelFunctionOpt.empty()) {
1405 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
1407 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
1408 <<
"' not found in module.";
1411 topLevelFunction = topLevelFunctionOpt;
1415 auto funcOps = moduleOp.getOps<FuncOp>();
1416 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
1417 topLevelFunction = (*funcOps.begin()).getSymName().str();
1419 moduleOp.emitError()
1420 <<
"Module contains multiple functions, but no top level "
1421 "function was set. Please see --top-level-function";
1442 using OpRewritePattern::OpRewritePattern;
1443 LogicalResult matchAndRewrite(mlir::ModuleOp,
1444 PatternRewriter &)
const override {
1449 ConversionTarget target(getContext());
1450 target.addLegalDialect<calyx::CalyxDialect>();
1451 target.addLegalDialect<scf::SCFDialect>();
1452 target.addIllegalDialect<hw::HWDialect>();
1453 target.addIllegalDialect<comb::CombDialect>();
1456 target.addIllegalOp<scf::ForOp>();
1459 target.addIllegalDialect<FuncDialect>();
1460 target.addIllegalDialect<ArithDialect>();
1461 target.addLegalOp<AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
1462 XOrIOp, OrIOp, ExtUIOp, TruncIOp, CondBranchOp, BranchOp,
1463 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp, ReturnOp,
1464 arith::ConstantOp, IndexCastOp, FuncOp, ExtSIOp>();
1466 RewritePatternSet legalizePatterns(&getContext());
1467 legalizePatterns.add<DummyPattern>(&getContext());
1468 DenseSet<Operation *> legalizedOps;
1469 if (applyPartialConversion(getOperation(), target,
1470 std::move(legalizePatterns))
1481 template <
typename TPattern,
typename... PatternArgs>
1483 PatternArgs &&...args) {
1484 RewritePatternSet ps(&getContext());
1490 template <
typename TPattern,
typename... PatternArgs>
1492 PatternArgs &&...args) {
1493 RewritePatternSet ps(&getContext());
1494 ps.add<TPattern>(&getContext(), args...);
1501 "Should only apply 1 partial lowering pattern at once");
1507 GreedyRewriteConfig config;
1508 config.enableRegionSimplification =
1509 mlir::GreedySimplifyRegionLevel::Disabled;
1511 config.maxIterations = 1;
1516 (void)applyPatternsAndFoldGreedily(getOperation(), std::move(
pattern),
1526 void LoopScheduleToCalyxPass::runOnOperation() {
1531 std::string topLevelFunction;
1532 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
1533 signalPassFailure();
1538 if (failed(labelEntryPoint(topLevelFunction))) {
1539 signalPassFailure();
1542 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
1553 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
1554 SmallVector<LoweringPattern, 8> loweringPatterns;
1558 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
1562 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
1566 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
1570 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
1576 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
1580 addOncePattern<BuildPipelineRegs>(loweringPatterns, patternState, funcMap,
1590 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
1594 addOncePattern<BuildPipelineGroups>(loweringPatterns, patternState, funcMap,
1600 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
1605 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
1610 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
1616 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
1620 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
1625 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
1629 for (
auto &pat : loweringPatterns) {
1632 pat.strategy == LoweringPattern::Strategy::Once);
1635 signalPassFailure();
1642 RewritePatternSet cleanupPatterns(&getContext());
1645 if (failed(applyPatternsAndFoldGreedily(getOperation(),
1646 std::move(cleanupPatterns)))) {
1647 signalPassFailure();
1651 if (ciderSourceLocationMetadata) {
1654 SmallVector<Attribute, 16> sourceLocations;
1655 getOperation()->walk([&](calyx::ComponentOp component) {
1659 MLIRContext *context = getOperation()->getContext();
1660 getOperation()->setAttr(
"calyx.metadata",
1672 return std::make_unique<pipelinetocalyx::LoopScheduleToCalyxPass>();
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
RewritePatternSet pattern
std::shared_ptr< calyx::CalyxLoweringState > loweringState
LogicalResult partialPatternRes
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.
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.
FuncOpPartialLoweringPatterns are patterns which intend to match on FuncOps and then perform their ow...
Holds common utilities used for scheduling when lowering to Calyx.
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.
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)
LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp, std::string &topLevelFunction)
LogicalResult runPartialPattern(RewritePatternSet &pattern, bool runOnce)
Holds additional information required for scheduling Pipeline pipelines.
void createPipelinePrologue(Operation *op, PatternRewriter &rewriter)
Create the pipeline prologue.
SmallVector< SmallVector< StringAttr > > getPipelinePrologue(Operation *op)
Get the pipeline prologue.
const DenseMap< unsigned, calyx::RegisterOp > & getPipelineRegs(Operation *stage)
Return a mapping of stage result indices to pipeline registers.
std::optional< TGroupOp > getNonPipelinedGroupFrom(Operation *op)
Returns the group registered for this non-pipelined value, and None otherwise.
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...
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
std::optional< int64_t > getBound() override
Value getConditionValue() override
Block * getBodyBlock() override
PipelineWhileOp(LoopSchedulePipelineOp op)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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 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)
unsigned handleZeroWidth(int64_t dim)
hw::ConstantOp createConstant(Location loc, OpBuilder &builder, ComponentOp component, size_t width, size_t value)
A helper function to create constants in the HW dialect.
calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, ComponentOp component, size_t width, Twine prefix)
Creates a RegisterOp, with input and output port bit widths defined by width.
bool noStoresToMemory(Value memoryReference)
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.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
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.