14 #include "../PassDetail.h"
21 #include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
22 #include "mlir/Conversion/LLVMCommon/Pattern.h"
23 #include "mlir/Dialect/Arith/IR/Arith.h"
24 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
25 #include "mlir/Dialect/Func/IR/FuncOps.h"
26 #include "mlir/Dialect/MemRef/IR/MemRef.h"
27 #include "mlir/IR/AsmState.h"
28 #include "mlir/IR/Matchers.h"
29 #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
30 #include "llvm/ADT/TypeSwitch.h"
42 namespace pipelinetocalyx {
51 : calyx::WhileOpInterface<LoopSchedulePipelineOp>(op) {}
54 return getOperation().getStagesBlock().getArguments();
57 Block *
getBodyBlock()
override {
return &getOperation().getStagesBlock(); }
62 return getOperation().getCondBlock().getTerminator()->getOperand(0);
66 return getOperation().getTripCount();
83 using Scheduleable = std::variant<calyx::GroupOp, PipelineScheduleable>;
91 calyx::GroupInterface group) {
92 operationToGroup[op] = group;
97 template <
typename TGroupOp = calyx::GroupInterface>
99 auto it = operationToGroup.find(op);
100 if (it == operationToGroup.end())
103 if constexpr (std::is_same<TGroupOp, calyx::GroupInterface>::value)
106 auto group = dyn_cast<TGroupOp>(it->second.getOperation());
107 assert(group &&
"Actual group type differed from expected group type");
113 assert(pipelineRegs[stage].count(idx) == 0);
114 assert(idx < stage->getNumResults());
115 pipelineRegs[stage][idx] =
reg;
119 const DenseMap<unsigned, calyx::RegisterOp> &
121 return pipelineRegs[stage];
126 pipelinePrologue[op].push_back(groupNames);
131 pipelineEpilogue[op].push_back(groupNames);
136 return pipelinePrologue[op];
141 auto stages = pipelinePrologue[op];
142 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
143 PatternRewriter::InsertionGuard g(rewriter);
144 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
145 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
146 for (
size_t j = 0; j < i + 1; ++j)
147 for (
auto group : stages[j])
148 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
154 auto stages = pipelineEpilogue[op];
155 for (
size_t i = 0, e = stages.size(); i < e; ++i) {
156 PatternRewriter::InsertionGuard g(rewriter);
157 auto parOp = rewriter.create<calyx::ParOp>(op->getLoc());
158 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
159 for (
size_t j = i, f = stages.size(); j < f; ++j)
160 for (
auto group : stages[j])
161 rewriter.create<calyx::EnableOp>(op->getLoc(), group);
172 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
pipelineRegs;
194 : calyx::ComponentLoweringStateInterface(component) {}
204 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
208 PatternRewriter &rewriter)
const override {
211 bool opBuiltSuccessfully =
true;
212 funcOp.walk([&](Operation *_op) {
213 opBuiltSuccessfully &=
214 TypeSwitch<mlir::Operation *, bool>(_op)
215 .template Case<arith::ConstantOp, ReturnOp, BranchOpInterface,
217 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
220 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp,
221 AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp, MulIOp,
222 DivUIOp, RemUIOp, IndexCastOp,
224 LoopScheduleTerminatorOp>(
225 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
226 .
template Case<FuncOp, LoopSchedulePipelineOp,
227 LoopScheduleRegisterOp,
228 LoopSchedulePipelineStageOp>([&](
auto) {
232 .Default([&](
auto op) {
233 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
237 return opBuiltSuccessfully ? WalkResult::advance()
238 : WalkResult::interrupt();
241 return success(opBuiltSuccessfully);
246 LogicalResult buildOp(PatternRewriter &rewriter,
247 BranchOpInterface brOp)
const;
248 LogicalResult buildOp(PatternRewriter &rewriter,
249 arith::ConstantOp constOp)
const;
250 LogicalResult buildOp(PatternRewriter &rewriter, AddIOp op)
const;
251 LogicalResult buildOp(PatternRewriter &rewriter, SubIOp op)
const;
252 LogicalResult buildOp(PatternRewriter &rewriter, MulIOp op)
const;
253 LogicalResult buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
254 LogicalResult buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
255 LogicalResult buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
256 LogicalResult buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
257 LogicalResult buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
258 LogicalResult buildOp(PatternRewriter &rewriter, AndIOp op)
const;
259 LogicalResult buildOp(PatternRewriter &rewriter, OrIOp op)
const;
260 LogicalResult buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
261 LogicalResult buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
262 LogicalResult buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
263 LogicalResult buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
264 LogicalResult buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
265 LogicalResult buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
266 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
267 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
268 LogicalResult buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
269 LogicalResult buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
270 LogicalResult buildOp(PatternRewriter &rewriter,
271 LoopScheduleTerminatorOp op)
const;
275 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
277 TypeRange srcTypes, TypeRange dstTypes)
const {
278 SmallVector<Type> types;
279 llvm::append_range(types, srcTypes);
280 llvm::append_range(types, dstTypes);
283 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
284 rewriter, op.getLoc(), types);
286 auto directions = calyxOp.portDirections();
287 SmallVector<Value, 4> opInputPorts;
288 SmallVector<Value, 4> opOutputPorts;
289 for (
auto dir : enumerate(directions)) {
291 opInputPorts.push_back(calyxOp.getResult(dir.index()));
293 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
296 opInputPorts.size() == op->getNumOperands() &&
297 opOutputPorts.size() == op->getNumResults() &&
298 "Expected an equal number of in/out ports in the Calyx library op with "
299 "respect to the number of operands/results of the source operation.");
302 auto group = createGroupForOp<TGroupOp>(rewriter, op);
303 rewriter.setInsertionPointToEnd(group.getBodyBlock());
304 for (
auto dstOp : enumerate(opInputPorts))
305 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(),
306 op->getOperand(dstOp.index()));
309 for (
auto res : enumerate(opOutputPorts)) {
310 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
312 op->getResult(res.index()).replaceAllUsesWith(res.value());
319 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
321 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
322 rewriter, op, op.getOperandTypes(), op->getResultTypes());
326 template <
typename TGroupOp>
328 Block *block = op->getBlock();
329 auto groupName = getState<ComponentLoweringState>().getUniqueName(
330 loweringState().blockName(block));
331 return calyx::createGroup<TGroupOp>(
332 rewriter, getState<ComponentLoweringState>().getComponentOp(),
333 op->getLoc(), groupName);
338 template <
typename TOpType,
typename TSrcOp>
340 TOpType opPipe, Value out)
const {
341 StringRef opName = TSrcOp::getOperationName().split(
".").second;
342 Location loc = op.getLoc();
343 Type
width = op.getResult().getType();
345 op.getResult().replaceAllUsesWith(out);
347 op.getLoc(), rewriter, getComponent(),
width.getIntOrFloatBitWidth(),
348 getState<ComponentLoweringState>().getUniqueName(opName));
350 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
351 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
354 rewriter.setInsertionPointToEnd(group.getBodyBlock());
355 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
356 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
358 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), out);
360 rewriter.create<calyx::AssignOp>(loc,
reg.getWriteEn(), opPipe.getDone());
361 rewriter.create<calyx::AssignOp>(
365 rewriter.create<calyx::GroupDoneOp>(loc,
reg.getDone());
368 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
369 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
371 getState<ComponentLoweringState>().registerEvaluatingGroup(
372 opPipe.getRight(), group);
380 calyx::GroupInterface group,
382 Operation::operand_range addressValues)
const {
383 IRRewriter::InsertionGuard guard(rewriter);
384 rewriter.setInsertionPointToEnd(group.getBody());
385 auto addrPorts = memoryInterface.
addrPorts();
386 if (addressValues.empty()) {
388 addrPorts.size() == 1 &&
389 "We expected a 1 dimensional memory of size 1 because there were no "
390 "address assignment values");
392 rewriter.create<calyx::AssignOp>(
396 assert(addrPorts.size() == addressValues.size() &&
397 "Mismatch between number of address ports of the provided memory "
398 "and address assignment values");
399 for (
auto address : enumerate(addressValues))
400 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
406 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
407 memref::LoadOp loadOp)
const {
408 Value memref = loadOp.getMemref();
409 auto memoryInterface =
410 getState<ComponentLoweringState>().getMemoryInterface(memref);
418 auto combGroup = createGroupForOp<calyx::CombGroupOp>(rewriter, loadOp);
419 assignAddressPorts(rewriter, loadOp.getLoc(), combGroup, memoryInterface,
420 loadOp.getIndices());
431 getState<ComponentLoweringState>().registerEvaluatingGroup(
432 loadOp.getResult(), combGroup);
434 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
435 assignAddressPorts(rewriter, loadOp.getLoc(), group, memoryInterface,
436 loadOp.getIndices());
447 loadOp.getLoc(), rewriter, getComponent(),
448 loadOp.getMemRefType().getElementTypeBitWidth(),
449 getState<ComponentLoweringState>().getUniqueName(
"load"));
451 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
452 reg, memoryInterface.readData());
453 loadOp.getResult().replaceAllUsesWith(
reg.getOut());
454 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
460 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
461 memref::StoreOp storeOp)
const {
462 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
463 storeOp.getMemref());
464 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
468 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
470 assignAddressPorts(rewriter, storeOp.getLoc(), group, memoryInterface,
471 storeOp.getIndices());
472 rewriter.setInsertionPointToEnd(group.getBodyBlock());
473 rewriter.create<calyx::AssignOp>(
474 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
475 rewriter.create<calyx::AssignOp>(
476 storeOp.getLoc(), memoryInterface.writeEn(),
477 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
478 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(),
479 memoryInterface.writeDone());
481 getState<ComponentLoweringState>().registerNonPipelineOperations(storeOp,
487 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
489 Location loc = mul.getLoc();
490 Type
width = mul.getResult().getType(), one = rewriter.getI1Type();
492 getState<ComponentLoweringState>()
493 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
495 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
496 rewriter, mul, mulPipe,
500 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
502 Location loc = div.getLoc();
503 Type
width = div.getResult().getType(), one = rewriter.getI1Type();
505 getState<ComponentLoweringState>()
506 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
508 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
509 rewriter, div, divPipe,
513 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
515 Location loc = rem.getLoc();
516 Type
width = rem.getResult().getType(), one = rewriter.getI1Type();
518 getState<ComponentLoweringState>()
519 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
521 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
522 rewriter, rem, remPipe,
526 template <
typename TAllocOp>
528 PatternRewriter &rewriter, TAllocOp allocOp) {
529 rewriter.setInsertionPointToStart(
531 MemRefType memtype = allocOp.getType();
532 SmallVector<int64_t> addrSizes;
533 SmallVector<int64_t> sizes;
534 for (int64_t dim : memtype.getShape()) {
535 sizes.push_back(dim);
540 if (sizes.empty() && addrSizes.empty()) {
542 addrSizes.push_back(1);
544 auto memoryOp = rewriter.create<calyx::MemoryOp>(
546 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
549 memoryOp->setAttr(
"external",
556 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
557 memref::AllocOp allocOp)
const {
558 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
561 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
562 memref::AllocaOp allocOp)
const {
563 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
566 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
567 LoopScheduleTerminatorOp term)
const {
568 if (term.getOperands().size() == 0)
572 auto *pipeline = term->getParentOp();
573 for (
size_t i = 0, e = pipeline->getNumResults(); i < e; ++i)
574 pipeline->getResult(i).replaceAllUsesWith(term.getResults()[i]);
579 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
580 BranchOpInterface brOp)
const {
585 Block *srcBlock = brOp->getBlock();
586 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
587 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
588 if (succOperands.empty())
591 std::string groupName = loweringState().blockName(srcBlock) +
"_to_" +
592 loweringState().blockName(succBlock.value());
593 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
594 brOp.getLoc(), groupName);
596 auto dstBlockArgRegs =
597 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
599 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
600 auto reg = dstBlockArgRegs[arg.index()];
603 getState<ComponentLoweringState>().getComponentOp(),
reg,
608 getState<ComponentLoweringState>().addBlockArgGroup(
609 srcBlock, succBlock.value(), groupOp);
616 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
617 ReturnOp retOp)
const {
618 if (retOp.getNumOperands() == 0)
621 std::string groupName =
622 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
623 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
624 retOp.getLoc(), groupName);
625 for (
auto op : enumerate(retOp.getOperands())) {
626 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
628 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
632 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
637 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
638 arith::ConstantOp constOp)
const {
642 auto hwConstOp = rewriter.replaceOpWithNewOp<hw::ConstantOp>(constOp, value);
643 hwConstOp->moveAfter(getComponent().getBodyBlock(),
644 getComponent().getBodyBlock()->begin());
648 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
650 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
652 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
654 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
656 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
658 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
660 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
662 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
664 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
666 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
668 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
670 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
672 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
674 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
676 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
678 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
681 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
683 switch (op.getPredicate()) {
684 case CmpIPredicate::eq:
685 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
686 case CmpIPredicate::ne:
687 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
688 case CmpIPredicate::uge:
689 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
690 case CmpIPredicate::ult:
691 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
692 case CmpIPredicate::ugt:
693 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
694 case CmpIPredicate::ule:
695 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
696 case CmpIPredicate::sge:
697 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
698 case CmpIPredicate::slt:
699 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
700 case CmpIPredicate::sgt:
701 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
702 case CmpIPredicate::sle:
703 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
705 llvm_unreachable(
"unsupported comparison predicate");
707 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
709 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
710 rewriter, op, {op.getOperand().getType()}, {op.getType()});
712 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
714 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
715 rewriter, op, {op.getOperand().getType()}, {op.getType()});
718 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
719 IndexCastOp op)
const {
722 unsigned targetBits = targetType.getIntOrFloatBitWidth();
723 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
724 LogicalResult res = success();
726 if (targetBits == sourceBits) {
729 op.getResult().replaceAllUsesWith(op.getOperand());
732 if (sourceBits > targetBits)
733 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
734 rewriter, op, {sourceType}, {targetType});
736 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
737 rewriter, op, {sourceType}, {targetType});
739 rewriter.eraseOp(op);
745 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
749 PatternRewriter &rewriter)
const override {
752 DenseMap<Value, unsigned> funcOpArgRewrites;
756 DenseMap<unsigned, unsigned> funcOpResultMapping;
764 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
768 SmallVector<calyx::PortInfo> inPorts, outPorts;
769 FunctionType funcType = funcOp.getFunctionType();
770 unsigned extMemCounter = 0;
771 for (
auto arg : enumerate(funcOp.getArguments())) {
772 if (arg.value().getType().isa<MemRefType>()) {
775 "ext_mem" + std::to_string(extMemoryCompPortIndices.size());
776 extMemoryCompPortIndices[arg.value()] = {inPorts.size(),
779 extMemCounter++, inPorts, outPorts);
782 auto inName =
"in" + std::to_string(arg.index());
783 funcOpArgRewrites[arg.value()] = inPorts.size();
785 rewriter.getStringAttr(inName),
791 for (
auto res : enumerate(funcType.getResults())) {
792 funcOpResultMapping[res.index()] = outPorts.size();
794 rewriter.getStringAttr(
"out" + std::to_string(res.index())),
801 auto ports = inPorts;
802 llvm::append_range(ports, outPorts);
806 auto compOp = rewriter.create<calyx::ComponentOp>(
807 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
810 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
813 functionMapping[funcOp] = compOp;
818 for (
auto &mapping : funcOpArgRewrites)
819 mapping.getFirst().replaceAllUsesWith(
820 compOp.getArgument(mapping.getSecond()));
823 for (
auto extMemPortIndices : extMemoryCompPortIndices) {
827 unsigned inPortsIt = extMemPortIndices.getSecond().first;
828 unsigned outPortsIt = extMemPortIndices.getSecond().second +
829 compOp.getInputPortInfo().size();
830 extMemPorts.
readData = compOp.getArgument(inPortsIt++);
831 extMemPorts.
writeDone = compOp.getArgument(inPortsIt);
832 extMemPorts.
writeData = compOp.getArgument(outPortsIt++);
833 unsigned nAddresses = extMemPortIndices.getFirst()
838 for (
unsigned j = 0; j < nAddresses; ++j)
839 extMemPorts.
addrPorts.push_back(compOp.getArgument(outPortsIt++));
840 extMemPorts.
writeEn = compOp.getArgument(outPortsIt);
844 compState->registerMemoryInterface(extMemPortIndices.getFirst(),
857 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
861 PatternRewriter &rewriter)
const override {
862 LogicalResult res = success();
863 funcOp.walk([&](Operation *op) {
864 if (!isa<LoopSchedulePipelineOp>(op))
865 return WalkResult::advance();
869 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
877 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
878 std::string name = getState<ComponentLoweringState>()
881 "_arg" + std::to_string(arg.index());
884 arg.value().getType().getIntOrFloatBitWidth(), name);
885 getState<ComponentLoweringState>().addLoopIterReg(whileOp,
reg,
887 arg.value().replaceAllUsesWith(
reg.getOut());
891 ->getArgument(arg.index())
892 .replaceAllUsesWith(
reg.getOut());
896 SmallVector<calyx::GroupOp> initGroups;
897 auto numOperands = whileOp.
getOperation()->getNumOperands();
898 for (
size_t i = 0; i < numOperands; ++i) {
900 getState<ComponentLoweringState>().buildLoopIterArgAssignments(
902 getState<ComponentLoweringState>().getComponentOp(),
903 getState<ComponentLoweringState>().getUniqueName(
905 "_init_" + std::to_string(i),
907 initGroups.push_back(initGroupOp);
912 getState<ComponentLoweringState>().addBlockScheduleable(
917 return WalkResult::advance();
925 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
929 PatternRewriter &rewriter)
const override {
930 funcOp.walk([&](LoopScheduleRegisterOp op) {
932 auto *parent = op->getParentOp();
933 auto stage = dyn_cast<LoopSchedulePipelineStageOp>(parent);
938 for (
auto &operand : op->getOpOperands()) {
939 unsigned i = operand.getOperandNumber();
942 Value stageResult = stage.getResult(i);
943 bool isIterArg =
false;
944 for (
auto &use : stageResult.getUses()) {
945 if (
auto term = dyn_cast<LoopScheduleTerminatorOp>(use.getOwner())) {
946 if (use.getOperandNumber() < term.getIterArgs().size()) {
948 dyn_cast<LoopSchedulePipelineOp>(stage->getParentOp()));
949 auto reg = getState<ComponentLoweringState>().getLoopIterReg(
950 whileOp, use.getOperandNumber());
951 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
960 Value value = operand.get();
961 Type resultType = value.getType();
962 assert(resultType.isa<IntegerType>() &&
963 "unsupported pipeline result type");
964 auto name = SmallString<20>(
"stage_");
965 name += std::to_string(stage.getStageNumber());
966 name +=
"_register_";
967 name += std::to_string(i);
968 unsigned width = resultType.getIntOrFloatBitWidth();
971 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
985 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
989 PatternRewriter &rewriter)
const override {
990 for (
auto pipeline : funcOp.getOps<LoopSchedulePipelineOp>())
992 pipeline.getStagesBlock().getOps<LoopSchedulePipelineStageOp>())
993 if (failed(buildStageGroups(pipeline, stage, rewriter)))
1000 LoopSchedulePipelineStageOp stage,
1001 PatternRewriter &rewriter)
const {
1003 auto pipelineRegisters =
1004 getState<ComponentLoweringState>().getPipelineRegs(stage);
1008 size_t numStages = whileOp.getStagesBlock().getOperations().size() - 1;
1012 SmallVector<StringAttr> prologueGroups, epilogueGroups;
1014 auto updatePrologueAndEpilogue = [&](calyx::GroupOp group) {
1016 getState<ComponentLoweringState>().addBlockScheduleable(stage->getBlock(),
1025 unsigned stageNumber = stage.getStageNumber();
1026 if (stageNumber < numStages - 1)
1027 prologueGroups.push_back(group.getSymNameAttr());
1028 if (stageNumber > 0)
1029 epilogueGroups.push_back(group.getSymNameAttr());
1032 MutableArrayRef<OpOperand> operands =
1033 stage.getBodyBlock().getTerminator()->getOpOperands();
1034 bool isStageWithNoPipelinedValues =
1035 operands.empty() && !stage.getBodyBlock().empty();
1036 if (isStageWithNoPipelinedValues) {
1039 for (
auto &op : stage.getBodyBlock())
1040 if (
auto group = getState<ComponentLoweringState>()
1041 .getNonPipelinedGroupFrom<calyx::GroupOp>(&op))
1042 updatePrologueAndEpilogue(*group);
1045 for (
auto &operand : operands) {
1046 unsigned i = operand.getOperandNumber();
1047 Value value = operand.get();
1050 auto pipelineRegister = pipelineRegisters[i];
1053 calyx::GroupInterface evaluatingGroup =
1054 getState<ComponentLoweringState>().getEvaluatingGroup(value);
1057 calyx::GroupOp group;
1061 if (
auto combGroup =
1062 dyn_cast<calyx::CombGroupOp>(evaluatingGroup.getOperation()))
1064 convertCombToSeqGroup(combGroup, pipelineRegister, value, rewriter);
1067 replaceGroupRegister(evaluatingGroup, pipelineRegister, rewriter);
1070 stage.getResult(i).replaceAllUsesWith(pipelineRegister.getOut());
1072 updatePrologueAndEpilogue(group);
1078 if (!prologueGroups.empty())
1079 getState<ComponentLoweringState>().addPipelinePrologue(whileOp,
1081 if (!epilogueGroups.empty())
1082 getState<ComponentLoweringState>().addPipelineEpilogue(whileOp,
1089 calyx::RegisterOp pipelineRegister,
1091 PatternRewriter &rewriter)
const {
1093 PatternRewriter::InsertionGuard g(rewriter);
1094 rewriter.setInsertionPoint(combGroup);
1095 auto group = rewriter.create<calyx::GroupOp>(combGroup.getLoc(),
1096 combGroup.getName());
1097 rewriter.cloneRegionBefore(combGroup.getBodyRegion(),
1098 &group.getBody().front());
1099 group.getBodyRegion().back().erase();
1100 rewriter.eraseOp(combGroup);
1104 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
1105 pipelineRegister, value);
1108 for (
auto assign : group.getOps<calyx::AssignOp>())
1109 getState<ComponentLoweringState>().registerEvaluatingGroup(
1110 assign.getSrc(), group);
1116 calyx::RegisterOp pipelineRegister,
1117 PatternRewriter &rewriter)
const {
1118 auto group = cast<calyx::GroupOp>(evaluatingGroup.getOperation());
1121 auto doneOp = group.getDoneOp();
1123 cast<calyx::RegisterOp>(doneOp.getSrc().cast<OpResult>().getOwner());
1124 auto tempIn = tempReg.getIn();
1125 auto tempWriteEn = tempReg.getWriteEn();
1128 for (
auto assign : group.getOps<calyx::AssignOp>()) {
1129 if (assign.getDest() == tempIn)
1130 assign.getDestMutable().assign(pipelineRegister.getIn());
1131 else if (assign.getDest() == tempWriteEn)
1132 assign.getDestMutable().assign(pipelineRegister.getWriteEn());
1134 doneOp.getSrcMutable().assign(pipelineRegister.getDone());
1137 rewriter.eraseOp(tempReg);
1149 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1153 PatternRewriter &rewriter)
const override {
1154 auto *entryBlock = &funcOp.getBlocks().front();
1155 rewriter.setInsertionPointToStart(
1156 getComponent().getControlOp().getBodyBlock());
1157 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
1158 DenseSet<Block *> path;
1159 return buildCFGControl(path, rewriter, topLevelSeqOp.getBodyBlock(),
1160 nullptr, entryBlock);
1167 const DenseSet<Block *> &path,
1168 mlir::Block *parentCtrlBlock,
1169 mlir::Block *block)
const {
1170 auto compBlockScheduleables =
1171 getState<ComponentLoweringState>().getBlockScheduleables(block);
1172 auto loc = block->front().getLoc();
1174 if (compBlockScheduleables.size() > 1) {
1175 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
1176 parentCtrlBlock = seqOp.getBodyBlock();
1179 for (
auto &group : compBlockScheduleables) {
1180 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1181 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
1182 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1183 groupPtr->getSymName());
1184 }
else if (
auto *pipeSchedPtr = std::get_if<PipelineScheduleable>(&group);
1186 auto &whileOp = pipeSchedPtr->whileOp;
1189 buildWhileCtrlOp(whileOp, pipeSchedPtr->initGroups, rewriter);
1190 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
1192 rewriter.create<calyx::ParOp>(whileOp.getOperation()->getLoc());
1193 rewriter.setInsertionPointToEnd(whileBodyOp.getBodyBlock());
1196 auto bodyBlockScheduleables =
1197 getState<ComponentLoweringState>().getBlockScheduleables(
1198 whileOp.getBodyBlock());
1199 for (
auto &group : bodyBlockScheduleables)
1200 if (
auto *groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr)
1201 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1202 groupPtr->getSymName());
1204 return whileOp.getOperation()->emitError(
1205 "Unsupported block schedulable");
1208 PatternRewriter::InsertionGuard g(rewriter);
1209 rewriter.setInsertionPoint(whileCtrlOp);
1210 getState<ComponentLoweringState>().createPipelinePrologue(
1211 whileOp.getOperation(), rewriter);
1212 rewriter.setInsertionPointAfter(whileCtrlOp);
1213 getState<ComponentLoweringState>().createPipelineEpilogue(
1214 whileOp.getOperation(), rewriter);
1216 llvm_unreachable(
"Unknown scheduleable");
1227 const DenseSet<Block *> &path, Location loc,
1228 Block *from, Block *to,
1229 Block *parentCtrlBlock)
const {
1232 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1233 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
1234 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
1236 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
1237 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
1239 return buildCFGControl(path, rewriter, parentCtrlBlock, from, to);
1243 PatternRewriter &rewriter,
1244 mlir::Block *parentCtrlBlock,
1245 mlir::Block *preBlock,
1246 mlir::Block *block)
const {
1247 if (path.count(block) != 0)
1248 return preBlock->getTerminator()->emitError()
1249 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
1250 "'scf.for' operations.";
1252 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1253 LogicalResult bbSchedResult =
1254 scheduleBasicBlock(rewriter, path, parentCtrlBlock, block);
1255 if (bbSchedResult.failed())
1256 return bbSchedResult;
1259 auto successors = block->getSuccessors();
1260 auto nSuccessors = successors.size();
1261 if (nSuccessors > 0) {
1262 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
1264 if (nSuccessors > 1) {
1268 assert(nSuccessors == 2 &&
1269 "only conditional branches supported for now...");
1271 auto cond = brOp->getOperand(0);
1272 auto condGroup = getState<ComponentLoweringState>()
1273 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1277 auto ifOp = rewriter.create<calyx::IfOp>(
1278 brOp->getLoc(), cond, symbolAttr,
true);
1279 rewriter.setInsertionPointToStart(ifOp.getThenBody());
1280 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1281 rewriter.setInsertionPointToStart(ifOp.getElseBody());
1282 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1284 bool trueBrSchedSuccess =
1285 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
1286 thenSeqOp.getBodyBlock())
1288 bool falseBrSchedSuccess =
true;
1289 if (trueBrSchedSuccess) {
1290 falseBrSchedSuccess =
1291 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
1292 elseSeqOp.getBodyBlock())
1296 return success(trueBrSchedSuccess && falseBrSchedSuccess);
1299 return schedulePath(rewriter, path, brOp.getLoc(), block,
1300 successors.front(), parentCtrlBlock);
1307 SmallVector<calyx::GroupOp> initGroups,
1308 PatternRewriter &rewriter)
const {
1309 Location loc = whileOp.
getLoc();
1313 PatternRewriter::InsertionGuard g(rewriter);
1314 auto parOp = rewriter.create<calyx::ParOp>(loc);
1315 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
1316 for (calyx::GroupOp group : initGroups)
1317 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
1322 auto condGroup = getState<ComponentLoweringState>()
1323 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1326 auto whileCtrlOp = rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
1329 if (
auto bound = whileOp.
getBound()) {
1331 auto prologue = getState<ComponentLoweringState>().getPipelinePrologue(
1333 auto unrolledBound = *bound - prologue.size();
1334 whileCtrlOp->setAttr(
"bound", rewriter.getI64IntegerAttr(unrolledBound));
1344 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1347 PatternRewriter &)
const override {
1348 funcOp.walk([&](memref::LoadOp loadOp) {
1354 loadOp.getResult().replaceAllUsesWith(
1355 getState<ComponentLoweringState>()
1356 .getMemoryInterface(loadOp.getMemref())
1367 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1370 PatternRewriter &rewriter)
const override {
1371 rewriter.eraseOp(funcOp);
1377 PatternRewriter &rewriter)
const override {
1390 partialPatternRes(success()) {}
1391 void runOnOperation()
override;
1394 std::string &topLevelFunction) {
1395 if (!topLevelFunctionOpt.empty()) {
1396 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
1398 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
1399 <<
"' not found in module.";
1402 topLevelFunction = topLevelFunctionOpt;
1406 auto funcOps = moduleOp.getOps<FuncOp>();
1407 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
1408 topLevelFunction = (*funcOps.begin()).getSymName().str();
1410 moduleOp.emitError()
1411 <<
"Module contains multiple functions, but no top level "
1412 "function was set. Please see --top-level-function";
1433 using OpRewritePattern::OpRewritePattern;
1434 LogicalResult matchAndRewrite(mlir::ModuleOp,
1435 PatternRewriter &)
const override {
1440 ConversionTarget target(getContext());
1441 target.addLegalDialect<calyx::CalyxDialect>();
1442 target.addLegalDialect<scf::SCFDialect>();
1443 target.addIllegalDialect<hw::HWDialect>();
1444 target.addIllegalDialect<comb::CombDialect>();
1447 target.addIllegalOp<scf::ForOp>();
1450 target.addIllegalDialect<FuncDialect>();
1451 target.addIllegalDialect<ArithDialect>();
1452 target.addLegalOp<AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
1453 XOrIOp, OrIOp, ExtUIOp, TruncIOp, CondBranchOp, BranchOp,
1454 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp, ReturnOp,
1455 arith::ConstantOp, IndexCastOp, FuncOp, ExtSIOp>();
1457 RewritePatternSet legalizePatterns(&getContext());
1458 legalizePatterns.add<DummyPattern>(&getContext());
1459 DenseSet<Operation *> legalizedOps;
1460 if (applyPartialConversion(getOperation(), target,
1461 std::move(legalizePatterns))
1472 template <
typename TPattern,
typename... PatternArgs>
1474 PatternArgs &&...args) {
1475 RewritePatternSet ps(&getContext());
1476 ps.add<TPattern>(&getContext(), partialPatternRes, args...);
1481 template <
typename TPattern,
typename... PatternArgs>
1483 PatternArgs &&...args) {
1484 RewritePatternSet ps(&getContext());
1485 ps.add<TPattern>(&getContext(), args...);
1491 assert(pattern.getNativePatterns().size() == 1 &&
1492 "Should only apply 1 partial lowering pattern at once");
1498 GreedyRewriteConfig config;
1499 config.enableRegionSimplification =
false;
1501 config.maxIterations = 1;
1506 (void)applyPatternsAndFoldGreedily(getOperation(), std::move(pattern),
1508 return partialPatternRes;
1513 std::shared_ptr<calyx::CalyxLoweringState> loweringState =
nullptr;
1516 void LoopScheduleToCalyxPass::runOnOperation() {
1518 loweringState.reset();
1519 partialPatternRes = LogicalResult::failure();
1521 std::string topLevelFunction;
1522 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
1523 signalPassFailure();
1528 if (failed(labelEntryPoint(topLevelFunction))) {
1529 signalPassFailure();
1532 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
1543 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
1544 SmallVector<LoweringPattern, 8> loweringPatterns;
1548 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
1552 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
1553 funcMap, *loweringState);
1556 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
1557 funcMap, *loweringState);
1560 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
1561 funcMap, *loweringState);
1566 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
1570 addOncePattern<BuildPipelineRegs>(loweringPatterns, patternState, funcMap,
1580 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
1584 addOncePattern<BuildPipelineGroups>(loweringPatterns, patternState, funcMap,
1590 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
1595 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
1600 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
1606 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
1610 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
1615 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
1619 for (
auto &pat : loweringPatterns) {
1620 LogicalResult partialPatternRes = runPartialPattern(
1622 pat.strategy == LoweringPattern::Strategy::Once);
1623 if (succeeded(partialPatternRes))
1625 signalPassFailure();
1632 RewritePatternSet cleanupPatterns(&getContext());
1635 if (failed(applyPatternsAndFoldGreedily(getOperation(),
1636 std::move(cleanupPatterns)))) {
1637 signalPassFailure();
1641 if (ciderSourceLocationMetadata) {
1644 SmallVector<Attribute, 16> sourceLocations;
1645 getOperation()->walk([&](calyx::ComponentOp component) {
1649 MLIRContext *context = getOperation()->getContext();
1650 getOperation()->setAttr(
"calyx.metadata",
1662 return std::make_unique<pipelinetocalyx::LoopScheduleToCalyxPass>();
assert(baseType &&"element must be base type")
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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 > writeEn
std::optional< Value > writeData
std::optional< Value > readData
std::optional< Value > writeDone
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.