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 if (memoryInterface.contentEnOpt().has_value()) {
480 rewriter.create<calyx::AssignOp>(
481 storeOp.getLoc(), memoryInterface.contentEn(),
482 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
484 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
486 getState<ComponentLoweringState>().registerNonPipelineOperations(storeOp,
492 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
494 Location loc = mul.getLoc();
495 Type
width = mul.getResult().getType(), one = rewriter.getI1Type();
497 getState<ComponentLoweringState>()
498 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
500 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
501 rewriter, mul, mulPipe,
505 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
507 Location loc = div.getLoc();
508 Type
width = div.getResult().getType(), one = rewriter.getI1Type();
510 getState<ComponentLoweringState>()
511 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
513 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
514 rewriter, div, divPipe,
518 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
520 Location loc = rem.getLoc();
521 Type
width = rem.getResult().getType(), one = rewriter.getI1Type();
523 getState<ComponentLoweringState>()
524 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
526 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
527 rewriter, rem, remPipe,
531 template <
typename TAllocOp>
533 PatternRewriter &rewriter, TAllocOp allocOp) {
534 rewriter.setInsertionPointToStart(
536 MemRefType memtype = allocOp.getType();
537 SmallVector<int64_t> addrSizes;
538 SmallVector<int64_t> sizes;
539 for (int64_t dim : memtype.getShape()) {
540 sizes.push_back(dim);
545 if (sizes.empty() && addrSizes.empty()) {
547 addrSizes.push_back(1);
549 auto memoryOp = rewriter.create<calyx::MemoryOp>(
551 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
554 memoryOp->setAttr(
"external",
561 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
562 memref::AllocOp allocOp)
const {
563 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
566 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
567 memref::AllocaOp allocOp)
const {
568 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
571 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
572 LoopScheduleTerminatorOp term)
const {
573 if (term.getOperands().size() == 0)
577 auto *pipeline = term->getParentOp();
578 for (
size_t i = 0, e = pipeline->getNumResults(); i < e; ++i)
579 pipeline->getResult(i).replaceAllUsesWith(term.getResults()[i]);
584 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
585 BranchOpInterface brOp)
const {
590 Block *srcBlock = brOp->getBlock();
591 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
592 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
593 if (succOperands.empty())
596 std::string groupName = loweringState().blockName(srcBlock) +
"_to_" +
597 loweringState().blockName(succBlock.value());
598 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
599 brOp.getLoc(), groupName);
601 auto dstBlockArgRegs =
602 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
604 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
605 auto reg = dstBlockArgRegs[arg.index()];
608 getState<ComponentLoweringState>().getComponentOp(),
reg,
613 getState<ComponentLoweringState>().addBlockArgGroup(
614 srcBlock, succBlock.value(), groupOp);
621 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
622 ReturnOp retOp)
const {
623 if (retOp.getNumOperands() == 0)
626 std::string groupName =
627 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
628 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
629 retOp.getLoc(), groupName);
630 for (
auto op : enumerate(retOp.getOperands())) {
631 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
633 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
637 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
642 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
643 arith::ConstantOp constOp)
const {
647 auto hwConstOp = rewriter.replaceOpWithNewOp<
hw::ConstantOp>(constOp, value);
648 hwConstOp->moveAfter(getComponent().getBodyBlock(),
649 getComponent().getBodyBlock()->begin());
653 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
655 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
657 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
659 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
661 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
663 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
665 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
667 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
669 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
671 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
673 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
675 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
677 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
679 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
681 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
683 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
686 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
688 switch (op.getPredicate()) {
689 case CmpIPredicate::eq:
690 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
691 case CmpIPredicate::ne:
692 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
693 case CmpIPredicate::uge:
694 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
695 case CmpIPredicate::ult:
696 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
697 case CmpIPredicate::ugt:
698 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
699 case CmpIPredicate::ule:
700 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
701 case CmpIPredicate::sge:
702 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
703 case CmpIPredicate::slt:
704 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
705 case CmpIPredicate::sgt:
706 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
707 case CmpIPredicate::sle:
708 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
710 llvm_unreachable(
"unsupported comparison predicate");
712 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
714 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
715 rewriter, op, {op.getOperand().getType()}, {op.getType()});
717 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
719 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
720 rewriter, op, {op.getOperand().getType()}, {op.getType()});
723 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
724 IndexCastOp op)
const {
727 unsigned targetBits = targetType.getIntOrFloatBitWidth();
728 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
729 LogicalResult res = success();
731 if (targetBits == sourceBits) {
734 op.getResult().replaceAllUsesWith(op.getOperand());
737 if (sourceBits > targetBits)
738 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
739 rewriter, op, {sourceType}, {targetType});
741 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
742 rewriter, op, {sourceType}, {targetType});
744 rewriter.eraseOp(op);
750 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
754 PatternRewriter &rewriter)
const override {
757 DenseMap<Value, unsigned> funcOpArgRewrites;
761 DenseMap<unsigned, unsigned> funcOpResultMapping;
769 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
773 SmallVector<calyx::PortInfo> inPorts, outPorts;
774 FunctionType funcType = funcOp.getFunctionType();
775 unsigned extMemCounter = 0;
776 for (
auto arg : enumerate(funcOp.getArguments())) {
777 if (arg.value().getType().isa<MemRefType>()) {
780 "ext_mem" + std::to_string(extMemoryCompPortIndices.size());
781 extMemoryCompPortIndices[arg.value()] = {inPorts.size(),
784 extMemCounter++, inPorts, outPorts);
787 auto inName =
"in" + std::to_string(arg.index());
788 funcOpArgRewrites[arg.value()] = inPorts.size();
790 rewriter.getStringAttr(inName),
796 for (
auto res : enumerate(funcType.getResults())) {
797 funcOpResultMapping[res.index()] = outPorts.size();
799 rewriter.getStringAttr(
"out" + std::to_string(res.index())),
806 auto ports = inPorts;
807 llvm::append_range(ports, outPorts);
811 auto compOp = rewriter.create<calyx::ComponentOp>(
812 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
815 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
818 functionMapping[funcOp] = compOp;
823 for (
auto &mapping : funcOpArgRewrites)
824 mapping.getFirst().replaceAllUsesWith(
825 compOp.getArgument(mapping.getSecond()));
828 for (
auto extMemPortIndices : extMemoryCompPortIndices) {
832 unsigned inPortsIt = extMemPortIndices.getSecond().first;
833 unsigned outPortsIt = extMemPortIndices.getSecond().second +
834 compOp.getInputPortInfo().size();
835 extMemPorts.
readData = compOp.getArgument(inPortsIt++);
836 extMemPorts.
done = compOp.getArgument(inPortsIt);
837 extMemPorts.
writeData = compOp.getArgument(outPortsIt++);
838 unsigned nAddresses = extMemPortIndices.getFirst()
843 for (
unsigned j = 0; j < nAddresses; ++j)
844 extMemPorts.
addrPorts.push_back(compOp.getArgument(outPortsIt++));
845 extMemPorts.
writeEn = compOp.getArgument(outPortsIt);
849 compState->registerMemoryInterface(extMemPortIndices.getFirst(),
862 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
866 PatternRewriter &rewriter)
const override {
867 LogicalResult res = success();
868 funcOp.walk([&](Operation *op) {
869 if (!isa<LoopSchedulePipelineOp>(op))
870 return WalkResult::advance();
874 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
882 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
883 std::string name = getState<ComponentLoweringState>()
886 "_arg" + std::to_string(arg.index());
889 arg.value().getType().getIntOrFloatBitWidth(), name);
890 getState<ComponentLoweringState>().addLoopIterReg(whileOp,
reg,
892 arg.value().replaceAllUsesWith(
reg.getOut());
896 ->getArgument(arg.index())
897 .replaceAllUsesWith(
reg.getOut());
901 SmallVector<calyx::GroupOp> initGroups;
902 auto numOperands = whileOp.
getOperation()->getNumOperands();
903 for (
size_t i = 0; i < numOperands; ++i) {
905 getState<ComponentLoweringState>().buildLoopIterArgAssignments(
907 getState<ComponentLoweringState>().getComponentOp(),
908 getState<ComponentLoweringState>().getUniqueName(
910 "_init_" + std::to_string(i),
912 initGroups.push_back(initGroupOp);
917 getState<ComponentLoweringState>().addBlockScheduleable(
922 return WalkResult::advance();
930 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
934 PatternRewriter &rewriter)
const override {
935 funcOp.walk([&](LoopScheduleRegisterOp op) {
937 auto *parent = op->getParentOp();
938 auto stage = dyn_cast<LoopSchedulePipelineStageOp>(parent);
943 for (
auto &operand : op->getOpOperands()) {
944 unsigned i = operand.getOperandNumber();
947 Value stageResult = stage.getResult(i);
948 bool isIterArg =
false;
949 for (
auto &use : stageResult.getUses()) {
950 if (
auto term = dyn_cast<LoopScheduleTerminatorOp>(use.getOwner())) {
951 if (use.getOperandNumber() < term.getIterArgs().size()) {
953 dyn_cast<LoopSchedulePipelineOp>(stage->getParentOp()));
954 auto reg = getState<ComponentLoweringState>().getLoopIterReg(
955 whileOp, use.getOperandNumber());
956 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
965 Value value = operand.get();
966 Type resultType = value.getType();
967 assert(resultType.isa<IntegerType>() &&
968 "unsupported pipeline result type");
969 auto name = SmallString<20>(
"stage_");
970 name += std::to_string(stage.getStageNumber());
971 name +=
"_register_";
972 name += std::to_string(i);
973 unsigned width = resultType.getIntOrFloatBitWidth();
976 getState<ComponentLoweringState>().addPipelineReg(stage,
reg, i);
990 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
994 PatternRewriter &rewriter)
const override {
995 for (
auto pipeline : funcOp.getOps<LoopSchedulePipelineOp>())
997 pipeline.getStagesBlock().getOps<LoopSchedulePipelineStageOp>())
998 if (failed(buildStageGroups(pipeline, stage, rewriter)))
1005 LoopSchedulePipelineStageOp stage,
1006 PatternRewriter &rewriter)
const {
1008 auto pipelineRegisters =
1009 getState<ComponentLoweringState>().getPipelineRegs(stage);
1013 size_t numStages = whileOp.getStagesBlock().getOperations().size() - 1;
1017 SmallVector<StringAttr> prologueGroups, epilogueGroups;
1019 auto updatePrologueAndEpilogue = [&](calyx::GroupOp group) {
1021 getState<ComponentLoweringState>().addBlockScheduleable(stage->getBlock(),
1030 unsigned stageNumber = stage.getStageNumber();
1031 if (stageNumber < numStages - 1)
1032 prologueGroups.push_back(group.getSymNameAttr());
1033 if (stageNumber > 0)
1034 epilogueGroups.push_back(group.getSymNameAttr());
1037 MutableArrayRef<OpOperand> operands =
1038 stage.getBodyBlock().getTerminator()->getOpOperands();
1039 bool isStageWithNoPipelinedValues =
1040 operands.empty() && !stage.getBodyBlock().empty();
1041 if (isStageWithNoPipelinedValues) {
1044 for (
auto &op : stage.getBodyBlock())
1045 if (
auto group = getState<ComponentLoweringState>()
1046 .getNonPipelinedGroupFrom<calyx::GroupOp>(&op))
1047 updatePrologueAndEpilogue(*group);
1050 for (
auto &operand : operands) {
1051 unsigned i = operand.getOperandNumber();
1052 Value value = operand.get();
1055 auto pipelineRegister = pipelineRegisters[i];
1058 calyx::GroupInterface evaluatingGroup =
1059 getState<ComponentLoweringState>().getEvaluatingGroup(value);
1062 calyx::GroupOp group;
1066 if (
auto combGroup =
1067 dyn_cast<calyx::CombGroupOp>(evaluatingGroup.getOperation()))
1069 convertCombToSeqGroup(combGroup, pipelineRegister, value, rewriter);
1072 replaceGroupRegister(evaluatingGroup, pipelineRegister, rewriter);
1075 stage.getResult(i).replaceAllUsesWith(pipelineRegister.getOut());
1077 updatePrologueAndEpilogue(group);
1083 if (!prologueGroups.empty())
1084 getState<ComponentLoweringState>().addPipelinePrologue(whileOp,
1086 if (!epilogueGroups.empty())
1087 getState<ComponentLoweringState>().addPipelineEpilogue(whileOp,
1094 calyx::RegisterOp pipelineRegister,
1096 PatternRewriter &rewriter)
const {
1098 PatternRewriter::InsertionGuard g(rewriter);
1099 rewriter.setInsertionPoint(combGroup);
1100 auto group = rewriter.create<calyx::GroupOp>(combGroup.getLoc(),
1101 combGroup.getName());
1102 rewriter.cloneRegionBefore(combGroup.getBodyRegion(),
1103 &group.getBody().front());
1104 group.getBodyRegion().back().erase();
1105 rewriter.eraseOp(combGroup);
1109 rewriter, group, getState<ComponentLoweringState>().getComponentOp(),
1110 pipelineRegister, value);
1113 for (
auto assign : group.getOps<calyx::AssignOp>())
1114 getState<ComponentLoweringState>().registerEvaluatingGroup(
1115 assign.getSrc(), group);
1121 calyx::RegisterOp pipelineRegister,
1122 PatternRewriter &rewriter)
const {
1123 auto group = cast<calyx::GroupOp>(evaluatingGroup.getOperation());
1126 auto doneOp = group.getDoneOp();
1128 cast<calyx::RegisterOp>(doneOp.getSrc().cast<OpResult>().getOwner());
1129 auto tempIn = tempReg.getIn();
1130 auto tempWriteEn = tempReg.getWriteEn();
1133 for (
auto assign : group.getOps<calyx::AssignOp>()) {
1134 if (assign.getDest() == tempIn)
1135 assign.getDestMutable().assign(pipelineRegister.getIn());
1136 else if (assign.getDest() == tempWriteEn)
1137 assign.getDestMutable().assign(pipelineRegister.getWriteEn());
1139 doneOp.getSrcMutable().assign(pipelineRegister.getDone());
1142 rewriter.eraseOp(tempReg);
1154 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1158 PatternRewriter &rewriter)
const override {
1159 auto *entryBlock = &funcOp.getBlocks().front();
1160 rewriter.setInsertionPointToStart(
1161 getComponent().getControlOp().getBodyBlock());
1162 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
1163 DenseSet<Block *> path;
1164 return buildCFGControl(path, rewriter, topLevelSeqOp.getBodyBlock(),
1165 nullptr, entryBlock);
1172 const DenseSet<Block *> &path,
1173 mlir::Block *parentCtrlBlock,
1174 mlir::Block *block)
const {
1175 auto compBlockScheduleables =
1176 getState<ComponentLoweringState>().getBlockScheduleables(block);
1177 auto loc = block->front().getLoc();
1179 if (compBlockScheduleables.size() > 1) {
1180 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
1181 parentCtrlBlock = seqOp.getBodyBlock();
1184 for (
auto &group : compBlockScheduleables) {
1185 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1186 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
1187 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1188 groupPtr->getSymName());
1189 }
else if (
auto *pipeSchedPtr = std::get_if<PipelineScheduleable>(&group);
1191 auto &whileOp = pipeSchedPtr->whileOp;
1194 buildWhileCtrlOp(whileOp, pipeSchedPtr->initGroups, rewriter);
1195 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
1197 rewriter.create<calyx::ParOp>(whileOp.getOperation()->getLoc());
1198 rewriter.setInsertionPointToEnd(whileBodyOp.getBodyBlock());
1201 auto bodyBlockScheduleables =
1202 getState<ComponentLoweringState>().getBlockScheduleables(
1203 whileOp.getBodyBlock());
1204 for (
auto &group : bodyBlockScheduleables)
1205 if (
auto *groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr)
1206 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1207 groupPtr->getSymName());
1209 return whileOp.getOperation()->emitError(
1210 "Unsupported block schedulable");
1213 PatternRewriter::InsertionGuard g(rewriter);
1214 rewriter.setInsertionPoint(whileCtrlOp);
1215 getState<ComponentLoweringState>().createPipelinePrologue(
1216 whileOp.getOperation(), rewriter);
1217 rewriter.setInsertionPointAfter(whileCtrlOp);
1218 getState<ComponentLoweringState>().createPipelineEpilogue(
1219 whileOp.getOperation(), rewriter);
1221 llvm_unreachable(
"Unknown scheduleable");
1232 const DenseSet<Block *> &path, Location loc,
1233 Block *from, Block *to,
1234 Block *parentCtrlBlock)
const {
1237 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1238 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
1239 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
1241 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
1242 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
1244 return buildCFGControl(path, rewriter, parentCtrlBlock, from, to);
1248 PatternRewriter &rewriter,
1249 mlir::Block *parentCtrlBlock,
1250 mlir::Block *preBlock,
1251 mlir::Block *block)
const {
1252 if (path.count(block) != 0)
1253 return preBlock->getTerminator()->emitError()
1254 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
1255 "'scf.for' operations.";
1257 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1258 LogicalResult bbSchedResult =
1259 scheduleBasicBlock(rewriter, path, parentCtrlBlock, block);
1260 if (bbSchedResult.failed())
1261 return bbSchedResult;
1264 auto successors = block->getSuccessors();
1265 auto nSuccessors = successors.size();
1266 if (nSuccessors > 0) {
1267 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
1269 if (nSuccessors > 1) {
1273 assert(nSuccessors == 2 &&
1274 "only conditional branches supported for now...");
1276 auto cond = brOp->getOperand(0);
1277 auto condGroup = getState<ComponentLoweringState>()
1278 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1282 auto ifOp = rewriter.create<calyx::IfOp>(
1283 brOp->getLoc(), cond, symbolAttr,
true);
1284 rewriter.setInsertionPointToStart(ifOp.getThenBody());
1285 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1286 rewriter.setInsertionPointToStart(ifOp.getElseBody());
1287 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
1289 bool trueBrSchedSuccess =
1290 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
1291 thenSeqOp.getBodyBlock())
1293 bool falseBrSchedSuccess =
true;
1294 if (trueBrSchedSuccess) {
1295 falseBrSchedSuccess =
1296 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
1297 elseSeqOp.getBodyBlock())
1301 return success(trueBrSchedSuccess && falseBrSchedSuccess);
1304 return schedulePath(rewriter, path, brOp.getLoc(), block,
1305 successors.front(), parentCtrlBlock);
1312 SmallVector<calyx::GroupOp> initGroups,
1313 PatternRewriter &rewriter)
const {
1314 Location loc = whileOp.
getLoc();
1318 PatternRewriter::InsertionGuard g(rewriter);
1319 auto parOp = rewriter.create<calyx::ParOp>(loc);
1320 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
1321 for (calyx::GroupOp group : initGroups)
1322 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
1327 auto condGroup = getState<ComponentLoweringState>()
1328 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
1331 auto whileCtrlOp = rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
1334 if (
auto bound = whileOp.
getBound()) {
1336 auto prologue = getState<ComponentLoweringState>().getPipelinePrologue(
1338 auto unrolledBound = *bound - prologue.size();
1339 whileCtrlOp->setAttr(
"bound", rewriter.getI64IntegerAttr(unrolledBound));
1349 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1352 PatternRewriter &)
const override {
1353 funcOp.walk([&](memref::LoadOp loadOp) {
1359 loadOp.getResult().replaceAllUsesWith(
1360 getState<ComponentLoweringState>()
1361 .getMemoryInterface(loadOp.getMemref())
1372 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1375 PatternRewriter &rewriter)
const override {
1376 rewriter.eraseOp(funcOp);
1382 PatternRewriter &rewriter)
const override {
1395 partialPatternRes(success()) {}
1396 void runOnOperation()
override;
1399 std::string &topLevelFunction) {
1400 if (!topLevelFunctionOpt.empty()) {
1401 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
1403 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
1404 <<
"' not found in module.";
1407 topLevelFunction = topLevelFunctionOpt;
1411 auto funcOps = moduleOp.getOps<FuncOp>();
1412 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
1413 topLevelFunction = (*funcOps.begin()).getSymName().str();
1415 moduleOp.emitError()
1416 <<
"Module contains multiple functions, but no top level "
1417 "function was set. Please see --top-level-function";
1438 using OpRewritePattern::OpRewritePattern;
1439 LogicalResult matchAndRewrite(mlir::ModuleOp,
1440 PatternRewriter &)
const override {
1445 ConversionTarget target(getContext());
1446 target.addLegalDialect<calyx::CalyxDialect>();
1447 target.addLegalDialect<scf::SCFDialect>();
1448 target.addIllegalDialect<hw::HWDialect>();
1449 target.addIllegalDialect<comb::CombDialect>();
1452 target.addIllegalOp<scf::ForOp>();
1455 target.addIllegalDialect<FuncDialect>();
1456 target.addIllegalDialect<ArithDialect>();
1457 target.addLegalOp<AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
1458 XOrIOp, OrIOp, ExtUIOp, TruncIOp, CondBranchOp, BranchOp,
1459 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp, ReturnOp,
1460 arith::ConstantOp, IndexCastOp, FuncOp, ExtSIOp>();
1462 RewritePatternSet legalizePatterns(&getContext());
1463 legalizePatterns.add<DummyPattern>(&getContext());
1464 DenseSet<Operation *> legalizedOps;
1465 if (applyPartialConversion(getOperation(), target,
1466 std::move(legalizePatterns))
1477 template <
typename TPattern,
typename... PatternArgs>
1479 PatternArgs &&...args) {
1480 RewritePatternSet ps(&getContext());
1481 ps.add<TPattern>(&getContext(), partialPatternRes, args...);
1486 template <
typename TPattern,
typename... PatternArgs>
1488 PatternArgs &&...args) {
1489 RewritePatternSet ps(&getContext());
1490 ps.add<TPattern>(&getContext(), args...);
1496 assert(pattern.getNativePatterns().size() == 1 &&
1497 "Should only apply 1 partial lowering pattern at once");
1503 GreedyRewriteConfig config;
1504 config.enableRegionSimplification =
false;
1506 config.maxIterations = 1;
1511 (void)applyPatternsAndFoldGreedily(getOperation(), std::move(pattern),
1513 return partialPatternRes;
1518 std::shared_ptr<calyx::CalyxLoweringState> loweringState =
nullptr;
1521 void LoopScheduleToCalyxPass::runOnOperation() {
1523 loweringState.reset();
1524 partialPatternRes = LogicalResult::failure();
1526 std::string topLevelFunction;
1527 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
1528 signalPassFailure();
1533 if (failed(labelEntryPoint(topLevelFunction))) {
1534 signalPassFailure();
1537 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
1548 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
1549 SmallVector<LoweringPattern, 8> loweringPatterns;
1553 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
1557 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
1558 funcMap, *loweringState);
1561 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
1562 funcMap, *loweringState);
1565 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
1566 funcMap, *loweringState);
1571 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
1575 addOncePattern<BuildPipelineRegs>(loweringPatterns, patternState, funcMap,
1585 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
1589 addOncePattern<BuildPipelineGroups>(loweringPatterns, patternState, funcMap,
1595 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
1600 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
1605 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
1611 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
1615 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
1620 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
1624 for (
auto &pat : loweringPatterns) {
1625 LogicalResult partialPatternRes = runPartialPattern(
1627 pat.strategy == LoweringPattern::Strategy::Once);
1628 if (succeeded(partialPatternRes))
1630 signalPassFailure();
1637 RewritePatternSet cleanupPatterns(&getContext());
1640 if (failed(applyPatternsAndFoldGreedily(getOperation(),
1641 std::move(cleanupPatterns)))) {
1642 signalPassFailure();
1646 if (ciderSourceLocationMetadata) {
1649 SmallVector<Attribute, 16> sourceLocations;
1650 getOperation()->walk([&](calyx::ComponentOp component) {
1654 MLIRContext *context = getOperation()->getContext();
1655 getOperation()->setAttr(
"calyx.metadata",
1667 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 > 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.