19#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
20#include "mlir/Conversion/LLVMCommon/Pattern.h"
21#include "mlir/Dialect/Arith/IR/Arith.h"
22#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
23#include "mlir/Dialect/Func/IR/FuncOps.h"
24#include "mlir/Dialect/MemRef/IR/MemRef.h"
25#include "mlir/Dialect/SCF/IR/SCF.h"
26#include "mlir/IR/AsmState.h"
27#include "mlir/IR/Matchers.h"
28#include "mlir/Pass/Pass.h"
29#include "mlir/Support/LogicalResult.h"
30#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
31#include "llvm/ADT/TypeSwitch.h"
32#include "llvm/Support/LogicalResult.h"
33#include "llvm/Support/raw_os_ostream.h"
34#include "llvm/Support/raw_ostream.h"
44#define GEN_PASS_DEF_SCFTOCALYX
45#include "circt/Conversion/Passes.h.inc"
50using namespace mlir::arith;
51using namespace mlir::cf;
54class ComponentLoweringStateInterface;
82 std::optional<int64_t>
getBound()
override {
return std::nullopt; }
144 Operation *operation = op.getOperation();
145 auto [it, succeeded] =
condReg.insert(std::make_pair(operation, regOp));
147 "A condition register was already set for this scf::IfOp!");
151 auto it =
condReg.find(op.getOperation());
158 Operation *operation = op.getOperation();
160 "A then group was already set for this scf::IfOp!\n");
165 auto it =
thenGroup.find(op.getOperation());
167 "No then group was set for this scf::IfOp!\n");
172 Operation *operation = op.getOperation();
174 "An else group was already set for this scf::IfOp!\n");
179 auto it =
elseGroup.find(op.getOperation());
181 "No else group was set for this scf::IfOp!\n");
187 "A register was already registered for the given yield result.\n");
188 assert(idx < op->getNumOperands());
198 auto it = regs.find(idx);
199 assert(it != regs.end() &&
"resultReg not found");
205 DenseMap<Operation *, calyx::RegisterOp>
condReg;
208 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
resultRegs;
218 OpBuilder &builder,
ScfWhileOp op, calyx::ComponentOp componentOp,
219 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
226 const DenseMap<unsigned, calyx::RegisterOp> &
237 SmallVector<calyx::GroupOp> groups) {
249 OpBuilder &builder,
ScfForOp op, calyx::ComponentOp componentOp,
250 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
279 auto cellOp = dyn_cast<calyx::CellInterface>(op);
280 assert(cellOp && !cellOp.isCombinational());
281 auto [it, succeeded] =
resultRegs.insert(std::make_pair(op, reg));
283 "A register was already set for this sequential operation!");
289 "No register was set for this sequential operation!");
323 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
325 mlir::Pass::Option<std::string> &writeJsonOpt)
328 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
332 PatternRewriter &rewriter)
const override {
335 bool opBuiltSuccessfully =
true;
336 funcOp.walk([&](Operation *_op) {
337 opBuiltSuccessfully &=
338 TypeSwitch<mlir::Operation *, bool>(_op)
340 arith::ConstantOp, ReturnOp, BranchOpInterface,
342 scf::YieldOp, scf::WhileOp, scf::ForOp, scf::IfOp,
343 scf::ParallelOp, scf::ReduceOp, scf::ExecuteRegionOp,
345 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
346 memref::StoreOp, memref::GetGlobalOp,
348 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
349 XOrIOp, OrIOp, ExtUIOp, ExtSIOp, TruncIOp, MulIOp, DivUIOp,
350 DivSIOp, RemUIOp, RemSIOp,
352 AddFOp, SubFOp, MulFOp, CmpFOp, FPToSIOp, SIToFPOp, DivFOp,
354 SelectOp, IndexCastOp, BitcastOp, CallOp>(
355 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
356 .
template Case<FuncOp, scf::ConditionOp>([&](
auto) {
360 .Default([&](
auto op) {
361 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
365 return opBuiltSuccessfully ? WalkResult::advance()
366 : WalkResult::interrupt();
370 if (
auto fileLoc = dyn_cast<mlir::FileLineColLoc>(funcOp->getLoc())) {
371 std::string filename = fileLoc.getFilename().str();
372 std::filesystem::path path(filename);
373 std::string jsonFileName =
writeJson.getValue() +
".json";
374 auto outFileName = path.parent_path().append(jsonFileName);
375 std::ofstream outFile(outFileName);
377 if (!outFile.is_open()) {
378 llvm::errs() <<
"Unable to open file: " << outFileName.string()
382 llvm::raw_os_ostream llvmOut(outFile);
383 llvm::json::OStream jsonOS(llvmOut, 2);
384 jsonOS.value(getState<ComponentLoweringState>().getExtMemData());
390 return success(opBuiltSuccessfully);
396 LogicalResult
buildOp(PatternRewriter &rewriter, scf::YieldOp yieldOp)
const;
397 LogicalResult
buildOp(PatternRewriter &rewriter,
398 BranchOpInterface brOp)
const;
399 LogicalResult
buildOp(PatternRewriter &rewriter,
400 arith::ConstantOp constOp)
const;
401 LogicalResult
buildOp(PatternRewriter &rewriter, SelectOp op)
const;
402 LogicalResult
buildOp(PatternRewriter &rewriter, AddIOp op)
const;
403 LogicalResult
buildOp(PatternRewriter &rewriter, SubIOp op)
const;
404 LogicalResult
buildOp(PatternRewriter &rewriter, MulIOp op)
const;
405 LogicalResult
buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
406 LogicalResult
buildOp(PatternRewriter &rewriter, DivSIOp op)
const;
407 LogicalResult
buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
408 LogicalResult
buildOp(PatternRewriter &rewriter, RemSIOp op)
const;
409 LogicalResult
buildOp(PatternRewriter &rewriter, AddFOp op)
const;
410 LogicalResult
buildOp(PatternRewriter &rewriter, SubFOp op)
const;
411 LogicalResult
buildOp(PatternRewriter &rewriter, MulFOp op)
const;
412 LogicalResult
buildOp(PatternRewriter &rewriter, CmpFOp op)
const;
413 LogicalResult
buildOp(PatternRewriter &rewriter, FPToSIOp op)
const;
414 LogicalResult
buildOp(PatternRewriter &rewriter, SIToFPOp op)
const;
415 LogicalResult
buildOp(PatternRewriter &rewriter, DivFOp op)
const;
416 LogicalResult
buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
417 LogicalResult
buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
418 LogicalResult
buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
419 LogicalResult
buildOp(PatternRewriter &rewriter, AndIOp op)
const;
420 LogicalResult
buildOp(PatternRewriter &rewriter, OrIOp op)
const;
421 LogicalResult
buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
422 LogicalResult
buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
423 LogicalResult
buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
424 LogicalResult
buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
425 LogicalResult
buildOp(PatternRewriter &rewriter, ExtSIOp op)
const;
426 LogicalResult
buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
427 LogicalResult
buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
428 LogicalResult
buildOp(PatternRewriter &rewriter, BitcastOp op)
const;
429 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
430 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
431 LogicalResult
buildOp(PatternRewriter &rewriter,
432 memref::GetGlobalOp op)
const;
433 LogicalResult
buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
434 LogicalResult
buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
435 LogicalResult
buildOp(PatternRewriter &rewriter, scf::WhileOp whileOp)
const;
436 LogicalResult
buildOp(PatternRewriter &rewriter, scf::ForOp forOp)
const;
437 LogicalResult
buildOp(PatternRewriter &rewriter, scf::IfOp ifOp)
const;
438 LogicalResult
buildOp(PatternRewriter &rewriter,
439 scf::ReduceOp reduceOp)
const;
440 LogicalResult
buildOp(PatternRewriter &rewriter,
441 scf::ParallelOp parallelOp)
const;
442 LogicalResult
buildOp(PatternRewriter &rewriter,
443 scf::ExecuteRegionOp executeRegionOp)
const;
444 LogicalResult
buildOp(PatternRewriter &rewriter, CallOp callOp)
const;
449 template <
typename TCalyxLibOp>
450 void setupCmpIOp(PatternRewriter &rewriter, CmpIOp cmpIOp, Operation *group,
451 calyx::RegisterOp &condReg, calyx::RegisterOp &resReg,
452 TCalyxLibOp calyxOp)
const {
456 StringRef opName = cmpIOp.getOperationName().split(
".").second;
457 Type width = cmpIOp.getResult().getType();
459 condReg = createRegister(
461 width.getIntOrFloatBitWidth(),
462 getState<ComponentLoweringState>().getUniqueName(opName));
464 for (
auto *user : cmpIOp->getUsers()) {
465 if (
auto ifOp = dyn_cast<scf::IfOp>(user))
466 getState<ComponentLoweringState>().setCondReg(ifOp, condReg);
470 lhsIsSeqOp != rhsIsSeqOp &&
471 "unexpected sequential operation on both sides; please open an issue");
475 cast<calyx::RegisterOp>(lhsIsSeqOp ? cmpIOp.getLhs().getDefiningOp()
476 : cmpIOp.getRhs().getDefiningOp());
478 auto groupOp = cast<calyx::GroupOp>(group);
479 getState<ComponentLoweringState>().addBlockScheduleable(cmpIOp->getBlock(),
482 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
483 auto loc = cmpIOp.getLoc();
485 (isa<calyx::EqLibOp, calyx::NeqLibOp, calyx::SleLibOp, calyx::SltLibOp,
486 calyx::LeLibOp, calyx::LtLibOp, calyx::GeLibOp, calyx::GtLibOp,
487 calyx::SgeLibOp, calyx::SgtLibOp>(calyxOp.getOperation())) &&
488 "Must be a Calyx comparison library operation.");
489 int64_t outputIndex = 2;
490 rewriter.create<calyx::AssignOp>(loc, condReg.getIn(),
491 calyxOp.getResult(outputIndex));
492 rewriter.create<calyx::AssignOp>(
493 loc, condReg.getWriteEn(),
494 createConstant(loc, rewriter,
495 getState<ComponentLoweringState>().getComponentOp(), 1,
497 rewriter.create<calyx::GroupDoneOp>(loc, condReg.getDone());
499 getState<ComponentLoweringState>().addSeqGuardCmpLibOp(cmpIOp);
450 void setupCmpIOp(PatternRewriter &rewriter, CmpIOp cmpIOp, Operation *group, {
…}
502 template <
typename CmpILibOp>
504 bool isIfOpGuard = std::any_of(op->getUsers().begin(), op->getUsers().end(),
505 [](
auto op) { return isa<scf::IfOp>(op); });
510 return buildLibraryOp<calyx::GroupOp, CmpILibOp>(rewriter, op);
511 return buildLibraryOp<calyx::CombGroupOp, CmpILibOp>(rewriter, op);
516 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
518 TypeRange srcTypes, TypeRange dstTypes)
const {
519 SmallVector<Type> types;
520 for (Type srcType : srcTypes)
522 for (Type dstType : dstTypes)
526 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
527 rewriter, op.getLoc(), types);
529 auto directions = calyxOp.portDirections();
530 SmallVector<Value, 4> opInputPorts;
531 SmallVector<Value, 4> opOutputPorts;
532 for (
auto dir : enumerate(directions)) {
534 opInputPorts.push_back(calyxOp.getResult(dir.index()));
536 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
539 opInputPorts.size() == op->getNumOperands() &&
540 opOutputPorts.size() == op->getNumResults() &&
541 "Expected an equal number of in/out ports in the Calyx library op with "
542 "respect to the number of operands/results of the source operation.");
545 auto group = createGroupForOp<TGroupOp>(rewriter, op);
547 bool isSeqCondCheck = isa<calyx::GroupOp>(group);
548 calyx::RegisterOp condReg =
nullptr, resReg =
nullptr;
549 if (isa<CmpIOp>(op) && isSeqCondCheck) {
550 auto cmpIOp = cast<CmpIOp>(op);
551 setupCmpIOp(rewriter, cmpIOp, group, condReg, resReg, calyxOp);
554 rewriter.setInsertionPointToEnd(group.getBodyBlock());
556 for (
auto dstOp : enumerate(opInputPorts)) {
559 : op->getOperand(dstOp.index());
560 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(), srcOp);
564 for (
auto res : enumerate(opOutputPorts)) {
565 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
567 auto dstOp = isSeqCondCheck ? condReg.getOut() : res.value();
568 op->getResult(res.index()).replaceAllUsesWith(dstOp);
576 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
578 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
579 rewriter, op, op.getOperandTypes(), op->getResultTypes());
583 template <
typename TGroupOp>
585 Block *block = op->getBlock();
586 auto groupName = getState<ComponentLoweringState>().getUniqueName(
588 return calyx::createGroup<TGroupOp>(
589 rewriter, getState<ComponentLoweringState>().getComponentOp(),
590 op->getLoc(), groupName);
595 template <
typename TOpType,
typename TSrcOp>
597 TOpType opPipe, Value out)
const {
598 StringRef opName = TSrcOp::getOperationName().split(
".").second;
599 Location loc = op.getLoc();
600 Type width = op.getResult().getType();
601 auto reg = createRegister(
602 op.getLoc(), rewriter,
getComponent(), width.getIntOrFloatBitWidth(),
603 getState<ComponentLoweringState>().getUniqueName(opName));
606 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
607 OpBuilder builder(group->getRegion(0));
608 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
611 rewriter.setInsertionPointToEnd(group.getBodyBlock());
612 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
613 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
615 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), out);
617 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(), opPipe.getDone());
622 rewriter.create<calyx::AssignOp>(
623 loc, opPipe.getGo(), c1,
626 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
630 op.getResult().replaceAllUsesWith(reg.getOut());
632 if (isa<calyx::AddFOpIEEE754>(opPipe)) {
633 auto opFOp = cast<calyx::AddFOpIEEE754>(opPipe);
635 if (isa<arith::AddFOp>(op)) {
636 subOp = createConstant(loc, rewriter,
getComponent(), 1,
639 subOp = createConstant(loc, rewriter,
getComponent(), 1,
642 rewriter.create<calyx::AssignOp>(loc, opFOp.getSubOp(), subOp);
643 }
else if (
auto opFOp =
644 dyn_cast<calyx::DivSqrtOpIEEE754>(opPipe.getOperation())) {
645 bool isSqrt = !isa<arith::DivFOp>(op);
647 createConstant(loc, rewriter,
getComponent(), 1, isSqrt);
648 rewriter.create<calyx::AssignOp>(loc, opFOp.getSqrtOp(), sqrtOp);
652 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
653 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
655 getState<ComponentLoweringState>().registerEvaluatingGroup(
656 opPipe.getRight(), group);
658 getState<ComponentLoweringState>().setSeqResReg(out.getDefiningOp(), reg);
663 template <
typename TCalyxLibOp,
typename TSrcOp>
665 unsigned inputWidth,
unsigned outputWidth,
666 StringRef signedPort)
const {
667 Location loc = op.getLoc();
668 IntegerType one = rewriter.getI1Type(),
669 inWidth = rewriter.getIntegerType(inputWidth),
670 outWidth = rewriter.getIntegerType(outputWidth);
672 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
673 rewriter, loc, {one, one, one, inWidth, one, outWidth, one});
675 StringRef opName = op.getOperationName().split(
".").second;
677 auto reg = createRegister(
678 loc, rewriter,
getComponent(), outWidth.getIntOrFloatBitWidth(),
679 getState<ComponentLoweringState>().getUniqueName(opName));
681 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
682 OpBuilder builder(group->getRegion(0));
683 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
686 rewriter.setInsertionPointToEnd(group.getBodyBlock());
687 rewriter.create<calyx::AssignOp>(loc, calyxOp.getIn(), op.getIn());
688 if (isa<calyx::FpToIntOpIEEE754>(calyxOp)) {
689 rewriter.create<calyx::AssignOp>(
690 loc, cast<calyx::FpToIntOpIEEE754>(calyxOp).getSignedOut(), c1);
691 }
else if (isa<calyx::IntToFpOpIEEE754>(calyxOp)) {
692 rewriter.create<calyx::AssignOp>(
693 loc, cast<calyx::IntToFpOpIEEE754>(calyxOp).getSignedIn(), c1);
695 op.getResult().replaceAllUsesWith(reg.getOut());
697 rewriter.create<calyx::AssignOp>(
698 loc, calyxOp.getGo(), c1,
700 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
708 calyx::GroupInterface group,
710 Operation::operand_range addressValues)
const {
711 IRRewriter::InsertionGuard guard(rewriter);
712 rewriter.setInsertionPointToEnd(group.getBody());
713 auto addrPorts = memoryInterface.
addrPorts();
714 if (addressValues.empty()) {
716 addrPorts.size() == 1 &&
717 "We expected a 1 dimensional memory of size 1 because there were no "
718 "address assignment values");
720 rewriter.create<calyx::AssignOp>(
724 assert(addrPorts.size() == addressValues.size() &&
725 "Mismatch between number of address ports of the provided memory "
726 "and address assignment values");
727 for (
auto address : enumerate(addressValues))
728 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
734 Value signal,
bool invert,
735 StringRef nameSuffix,
736 calyx::CompareFOpIEEE754 calyxCmpFOp,
737 calyx::GroupOp group)
const {
738 Location loc = calyxCmpFOp.getLoc();
739 IntegerType one = rewriter.getI1Type();
741 OpBuilder builder(group->getRegion(0));
742 auto reg = createRegister(
743 loc, rewriter, component, 1,
744 getState<ComponentLoweringState>().getUniqueName(nameSuffix));
745 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(),
746 calyxCmpFOp.getDone());
748 auto notLibOp = getState<ComponentLoweringState>()
749 .getNewLibraryOpInstance<calyx::NotLibOp>(
750 rewriter, loc, {one, one});
751 rewriter.create<calyx::AssignOp>(loc, notLibOp.getIn(), signal);
752 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), notLibOp.getOut());
753 getState<ComponentLoweringState>().registerEvaluatingGroup(
754 notLibOp.getOut(), group);
756 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), signal);
762 memref::LoadOp loadOp)
const {
763 Value memref = loadOp.getMemref();
764 auto memoryInterface =
765 getState<ComponentLoweringState>().getMemoryInterface(memref);
766 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
768 loadOp.getIndices());
770 rewriter.setInsertionPointToEnd(group.getBodyBlock());
775 createConstant(loadOp.getLoc(), rewriter,
getComponent(), 1, 1);
776 if (memoryInterface.readEnOpt().has_value()) {
779 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.readEn(),
781 regWriteEn = memoryInterface.done();
788 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
789 memoryInterface.done());
799 res = loadOp.getResult();
801 }
else if (memoryInterface.contentEnOpt().has_value()) {
806 rewriter.create<calyx::AssignOp>(loadOp.getLoc(),
807 memoryInterface.contentEn(), oneI1);
808 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.writeEn(),
810 regWriteEn = memoryInterface.done();
817 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
818 memoryInterface.done());
828 res = loadOp.getResult();
840 auto reg = createRegister(
842 loadOp.getMemRefType().getElementTypeBitWidth(),
843 getState<ComponentLoweringState>().getUniqueName(
"load"));
844 rewriter.setInsertionPointToEnd(group.getBodyBlock());
845 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), reg.getIn(),
846 memoryInterface.readData());
847 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), reg.getWriteEn(),
849 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(), reg.getDone());
850 loadOp.getResult().replaceAllUsesWith(reg.getOut());
854 getState<ComponentLoweringState>().registerEvaluatingGroup(res, group);
855 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
861 memref::StoreOp storeOp)
const {
862 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
863 storeOp.getMemref());
864 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
868 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
871 storeOp.getIndices());
872 rewriter.setInsertionPointToEnd(group.getBodyBlock());
873 rewriter.create<calyx::AssignOp>(
874 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
875 rewriter.create<calyx::AssignOp>(
876 storeOp.getLoc(), memoryInterface.writeEn(),
877 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
878 if (memoryInterface.contentEnOpt().has_value()) {
880 rewriter.create<calyx::AssignOp>(
881 storeOp.getLoc(), memoryInterface.contentEn(),
882 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
884 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
891 Location loc = mul.getLoc();
892 Type width = mul.getResult().getType(), one = rewriter.getI1Type();
894 getState<ComponentLoweringState>()
895 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
896 rewriter, loc, {one, one, one, width, width, width, one});
897 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
898 rewriter, mul, mulPipe,
904 Location loc = div.getLoc();
905 Type width = div.getResult().getType(), one = rewriter.getI1Type();
907 getState<ComponentLoweringState>()
908 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
909 rewriter, loc, {one, one, one, width, width, width, one});
910 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
911 rewriter, div, divPipe,
917 Location loc = div.getLoc();
918 Type width = div.getResult().getType(), one = rewriter.getI1Type();
920 getState<ComponentLoweringState>()
921 .getNewLibraryOpInstance<calyx::DivSPipeLibOp>(
922 rewriter, loc, {one, one, one, width, width, width, one});
923 return buildLibraryBinaryPipeOp<calyx::DivSPipeLibOp>(
924 rewriter, div, divPipe,
930 Location loc = rem.getLoc();
931 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
933 getState<ComponentLoweringState>()
934 .getNewLibraryOpInstance<calyx::RemUPipeLibOp>(
935 rewriter, loc, {one, one, one, width, width, width, one});
936 return buildLibraryBinaryPipeOp<calyx::RemUPipeLibOp>(
937 rewriter, rem, remPipe,
943 Location loc = rem.getLoc();
944 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
946 getState<ComponentLoweringState>()
947 .getNewLibraryOpInstance<calyx::RemSPipeLibOp>(
948 rewriter, loc, {one, one, one, width, width, width, one});
949 return buildLibraryBinaryPipeOp<calyx::RemSPipeLibOp>(
950 rewriter, rem, remPipe,
956 Location loc = addf.getLoc();
957 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
958 five = rewriter.getIntegerType(5),
959 width = rewriter.getIntegerType(
960 addf.getType().getIntOrFloatBitWidth());
962 getState<ComponentLoweringState>()
963 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
965 {one, one, one, one, one, width, width, three, width, five, one});
966 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, addf, addFOp,
972 Location loc = subf.getLoc();
973 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
974 five = rewriter.getIntegerType(5),
975 width = rewriter.getIntegerType(
976 subf.getType().getIntOrFloatBitWidth());
978 getState<ComponentLoweringState>()
979 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
981 {one, one, one, one, one, width, width, three, width, five, one});
982 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, subf, subFOp,
988 Location loc = mulf.getLoc();
989 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
990 five = rewriter.getIntegerType(5),
991 width = rewriter.getIntegerType(
992 mulf.getType().getIntOrFloatBitWidth());
994 getState<ComponentLoweringState>()
995 .getNewLibraryOpInstance<calyx::MulFOpIEEE754>(
997 {one, one, one, one, width, width, three, width, five, one});
998 return buildLibraryBinaryPipeOp<calyx::MulFOpIEEE754>(rewriter, mulf, mulFOp,
1003 CmpFOp cmpf)
const {
1004 Location loc = cmpf.getLoc();
1005 IntegerType one = rewriter.getI1Type(), five = rewriter.getIntegerType(5),
1006 width = rewriter.getIntegerType(
1007 cmpf.getLhs().getType().getIntOrFloatBitWidth());
1008 auto calyxCmpFOp = getState<ComponentLoweringState>()
1009 .getNewLibraryOpInstance<calyx::CompareFOpIEEE754>(
1011 {one, one, one, width, width, one, one, one, one,
1018 using CombLogic = PredicateInfo::CombLogic;
1019 using Port = PredicateInfo::InputPorts::Port;
1021 if (info.logic == CombLogic::None) {
1022 if (cmpf.getPredicate() == CmpFPredicate::AlwaysTrue) {
1023 cmpf.getResult().replaceAllUsesWith(c1);
1027 if (cmpf.getPredicate() == CmpFPredicate::AlwaysFalse) {
1028 cmpf.getResult().replaceAllUsesWith(c0);
1034 StringRef opName = cmpf.getOperationName().split(
".").second;
1037 getState<ComponentLoweringState>().getUniqueName(opName));
1040 auto group = createGroupForOp<calyx::GroupOp>(rewriter, cmpf);
1041 OpBuilder builder(group->getRegion(0));
1042 getState<ComponentLoweringState>().addBlockScheduleable(cmpf->getBlock(),
1045 rewriter.setInsertionPointToEnd(group.getBodyBlock());
1046 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getLeft(), cmpf.getLhs());
1047 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getRight(), cmpf.getRhs());
1049 bool signalingFlag =
false;
1050 switch (cmpf.getPredicate()) {
1051 case CmpFPredicate::UGT:
1052 case CmpFPredicate::UGE:
1053 case CmpFPredicate::ULT:
1054 case CmpFPredicate::ULE:
1055 case CmpFPredicate::OGT:
1056 case CmpFPredicate::OGE:
1057 case CmpFPredicate::OLT:
1058 case CmpFPredicate::OLE:
1059 signalingFlag =
true;
1061 case CmpFPredicate::UEQ:
1062 case CmpFPredicate::UNE:
1063 case CmpFPredicate::OEQ:
1064 case CmpFPredicate::ONE:
1065 case CmpFPredicate::UNO:
1066 case CmpFPredicate::ORD:
1067 case CmpFPredicate::AlwaysTrue:
1068 case CmpFPredicate::AlwaysFalse:
1069 signalingFlag =
false;
1075 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getSignaling(),
1076 signalingFlag ? c1 : c0);
1079 SmallVector<calyx::RegisterOp> inputRegs;
1080 for (
const auto &input : info.inputPorts) {
1082 switch (input.port) {
1084 signal = calyxCmpFOp.getEq();
1088 signal = calyxCmpFOp.getGt();
1092 signal = calyxCmpFOp.getLt();
1095 case Port::Unordered: {
1096 signal = calyxCmpFOp.getUnordered();
1100 std::string nameSuffix =
1101 (input.port == PredicateInfo::InputPorts::Port::Unordered)
1105 nameSuffix, calyxCmpFOp, group);
1106 inputRegs.push_back(signalReg);
1110 Value outputValue, doneValue;
1111 switch (info.logic) {
1112 case CombLogic::None: {
1114 outputValue = inputRegs[0].getOut();
1115 doneValue = inputRegs[0].getDone();
1118 case CombLogic::And: {
1119 auto outputLibOp = getState<ComponentLoweringState>()
1120 .getNewLibraryOpInstance<calyx::AndLibOp>(
1121 rewriter, loc, {one, one, one});
1122 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
1123 inputRegs[0].getOut());
1124 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
1125 inputRegs[1].getOut());
1127 outputValue = outputLibOp.getOut();
1130 case CombLogic::Or: {
1131 auto outputLibOp = getState<ComponentLoweringState>()
1132 .getNewLibraryOpInstance<calyx::OrLibOp>(
1133 rewriter, loc, {one, one, one});
1134 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
1135 inputRegs[0].getOut());
1136 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
1137 inputRegs[1].getOut());
1139 outputValue = outputLibOp.getOut();
1144 if (info.logic != CombLogic::None) {
1145 auto doneLibOp = getState<ComponentLoweringState>()
1146 .getNewLibraryOpInstance<calyx::AndLibOp>(
1147 rewriter, loc, {one, one, one});
1148 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getLeft(),
1149 inputRegs[0].getDone());
1150 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getRight(),
1151 inputRegs[1].getDone());
1152 doneValue = doneLibOp.getOut();
1156 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), outputValue);
1157 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(), doneValue);
1160 rewriter.create<calyx::AssignOp>(
1161 loc, calyxCmpFOp.getGo(), c1,
1163 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
1165 cmpf.getResult().replaceAllUsesWith(reg.getOut());
1168 getState<ComponentLoweringState>().registerEvaluatingGroup(outputValue,
1170 getState<ComponentLoweringState>().registerEvaluatingGroup(doneValue, group);
1171 getState<ComponentLoweringState>().registerEvaluatingGroup(
1172 calyxCmpFOp.getLeft(), group);
1173 getState<ComponentLoweringState>().registerEvaluatingGroup(
1174 calyxCmpFOp.getRight(), group);
1180 FPToSIOp fptosi)
const {
1181 return buildFpIntTypeCastOp<calyx::FpToIntOpIEEE754>(
1182 rewriter, fptosi, fptosi.getIn().getType().getIntOrFloatBitWidth(),
1183 fptosi.getOut().getType().getIntOrFloatBitWidth(),
"signedOut");
1187 SIToFPOp sitofp)
const {
1188 return buildFpIntTypeCastOp<calyx::IntToFpOpIEEE754>(
1189 rewriter, sitofp, sitofp.getIn().getType().getIntOrFloatBitWidth(),
1190 sitofp.getOut().getType().getIntOrFloatBitWidth(),
"signedIn");
1194 DivFOp divf)
const {
1195 Location loc = divf.getLoc();
1196 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
1197 five = rewriter.getIntegerType(5),
1198 width = rewriter.getIntegerType(
1199 divf.getType().getIntOrFloatBitWidth());
1200 auto divFOp = getState<ComponentLoweringState>()
1201 .getNewLibraryOpInstance<calyx::DivSqrtOpIEEE754>(
1205 width, three, width,
1207 return buildLibraryBinaryPipeOp<calyx::DivSqrtOpIEEE754>(
1208 rewriter, divf, divFOp, divFOp.getOut());
1211template <
typename TAllocOp>
1213 PatternRewriter &rewriter, TAllocOp allocOp) {
1214 rewriter.setInsertionPointToStart(
1216 MemRefType memtype = allocOp.getType();
1217 SmallVector<int64_t> addrSizes;
1218 SmallVector<int64_t> sizes;
1219 for (int64_t dim : memtype.getShape()) {
1220 sizes.push_back(dim);
1225 if (sizes.empty() && addrSizes.empty()) {
1227 addrSizes.push_back(1);
1229 auto memoryOp = rewriter.create<calyx::SeqMemoryOp>(
1231 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1235 memoryOp->setAttr(
"external",
1236 IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));
1240 unsigned elmTyBitWidth = memtype.getElementTypeBitWidth();
1241 assert(elmTyBitWidth <= 64 &&
"element bitwidth should not exceed 64");
1242 bool isFloat = !memtype.getElementType().isInteger();
1244 auto shape = allocOp.getType().getShape();
1246 std::reduce(shape.begin(), shape.end(), 1, std::multiplies<int>());
1253 if (!(shape.size() <= 1 || totalSize <= 1)) {
1254 allocOp.emitError(
"input memory dimension must be empty or one.");
1258 std::vector<uint64_t> flattenedVals(totalSize, 0);
1259 if (isa<memref::GetGlobalOp>(allocOp)) {
1260 auto getGlobalOp = cast<memref::GetGlobalOp>(allocOp);
1261 auto *symbolTableOp =
1262 getGlobalOp->template getParentWithTrait<mlir::OpTrait::SymbolTable>();
1263 auto globalOp = dyn_cast_or_null<memref::GlobalOp>(
1264 SymbolTable::lookupSymbolIn(symbolTableOp, getGlobalOp.getNameAttr()));
1266 auto cstAttr = llvm::dyn_cast_or_null<DenseElementsAttr>(
1267 globalOp.getConstantInitValue());
1269 for (
auto attr : cstAttr.template getValues<Attribute>()) {
1270 assert((isa<mlir::FloatAttr, mlir::IntegerAttr>(attr)) &&
1271 "memory attributes must be float or int");
1272 if (
auto fltAttr = dyn_cast<mlir::FloatAttr>(attr)) {
1273 flattenedVals[sizeCount++] =
1274 bit_cast<uint64_t>(fltAttr.getValueAsDouble());
1276 auto intAttr = dyn_cast<mlir::IntegerAttr>(attr);
1277 APInt value = intAttr.getValue();
1278 flattenedVals[sizeCount++] = *value.getRawData();
1282 rewriter.eraseOp(globalOp);
1285 llvm::json::Array result;
1286 result.reserve(std::max(
static_cast<int>(shape.size()), 1));
1288 Type elemType = memtype.getElementType();
1290 !elemType.isSignlessInteger() && !elemType.isUnsignedInteger();
1291 for (uint64_t bitValue : flattenedVals) {
1292 llvm::json::Value value = 0;
1296 value = bit_cast<double>(bitValue);
1298 APInt apInt(elmTyBitWidth, bitValue, isSigned,
1303 value =
static_cast<int64_t
>(apInt.getSExtValue());
1305 value = apInt.getZExtValue();
1307 result.push_back(std::move(value));
1310 componentState.
setDataField(memoryOp.getName(), result);
1311 std::string numType =
1312 memtype.getElementType().isInteger() ?
"bitnum" :
"ieee754_float";
1313 componentState.
setFormat(memoryOp.getName(), numType, isSigned,
1320 memref::AllocOp allocOp)
const {
1321 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1325 memref::AllocaOp allocOp)
const {
1326 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1330 memref::GetGlobalOp getGlobalOp)
const {
1331 return buildAllocOp(getState<ComponentLoweringState>(), rewriter,
1336 scf::YieldOp yieldOp)
const {
1337 if (yieldOp.getOperands().empty()) {
1338 if (
auto forOp = dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1342 auto inductionReg = getState<ComponentLoweringState>().getForLoopIterReg(
1345 Type regWidth = inductionReg.getOut().getType();
1347 SmallVector<Type> types(3, regWidth);
1348 auto addOp = getState<ComponentLoweringState>()
1349 .getNewLibraryOpInstance<calyx::AddLibOp>(
1350 rewriter, forOp.getLoc(), types);
1352 auto directions = addOp.portDirections();
1354 SmallVector<Value, 2> opInputPorts;
1356 for (
auto dir : enumerate(directions)) {
1357 switch (dir.value()) {
1359 opInputPorts.push_back(addOp.getResult(dir.index()));
1363 opOutputPort = addOp.getResult(dir.index());
1371 getState<ComponentLoweringState>().getComponentOp();
1372 SmallVector<StringRef, 4> groupIdentifier = {
1373 "incr", getState<ComponentLoweringState>().getUniqueName(forOp),
1374 "induction",
"var"};
1375 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1377 llvm::join(groupIdentifier,
"_"));
1378 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
1381 Value leftOp = opInputPorts.front();
1382 rewriter.create<calyx::AssignOp>(forOp.getLoc(), leftOp,
1383 inductionReg.getOut());
1385 Value rightOp = opInputPorts.back();
1386 rewriter.create<calyx::AssignOp>(
1387 forOp.getLoc(), rightOp,
1388 createConstant(forOp->getLoc(), rewriter,
componentOp,
1389 regWidth.getIntOrFloatBitWidth(),
1390 forOp.getConstantStep().value().getSExtValue()));
1392 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp,
1393 inductionReg, opOutputPort);
1395 getState<ComponentLoweringState>().setForLoopLatchGroup(forOpInterface,
1397 getState<ComponentLoweringState>().registerEvaluatingGroup(opOutputPort,
1401 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp()))
1404 if (
auto executeRegionOp =
1405 dyn_cast<scf::ExecuteRegionOp>(yieldOp->getParentOp()))
1408 return yieldOp.getOperation()->emitError()
1409 <<
"Unsupported empty yieldOp outside ForOp or IfOp.";
1412 if (dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1413 return yieldOp.getOperation()->emitError()
1414 <<
"Currently do not support non-empty yield operations inside for "
1415 "loops. Run --scf-for-to-while before running --scf-to-calyx.";
1418 if (
auto whileOp = dyn_cast<scf::WhileOp>(yieldOp->getParentOp())) {
1422 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1423 rewriter, whileOpInterface,
1424 getState<ComponentLoweringState>().getComponentOp(),
1425 getState<ComponentLoweringState>().getUniqueName(whileOp) +
1427 yieldOp->getOpOperands());
1428 getState<ComponentLoweringState>().setWhileLoopLatchGroup(whileOpInterface,
1433 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp())) {
1434 auto resultRegs = getState<ComponentLoweringState>().getResultRegs(ifOp);
1436 if (yieldOp->getParentRegion() == &ifOp.getThenRegion()) {
1437 auto thenGroup = getState<ComponentLoweringState>().getThenGroup(ifOp);
1438 for (
auto op : enumerate(yieldOp.getOperands())) {
1440 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1441 buildAssignmentsForRegisterWrite(
1442 rewriter, thenGroup,
1443 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1445 getState<ComponentLoweringState>().registerEvaluatingGroup(
1446 ifOp.getResult(op.index()), thenGroup);
1450 if (!ifOp.getElseRegion().empty() &&
1451 (yieldOp->getParentRegion() == &ifOp.getElseRegion())) {
1452 auto elseGroup = getState<ComponentLoweringState>().getElseGroup(ifOp);
1453 for (
auto op : enumerate(yieldOp.getOperands())) {
1455 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1456 buildAssignmentsForRegisterWrite(
1457 rewriter, elseGroup,
1458 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1460 getState<ComponentLoweringState>().registerEvaluatingGroup(
1461 ifOp.getResult(op.index()), elseGroup);
1469 BranchOpInterface brOp)
const {
1474 Block *srcBlock = brOp->getBlock();
1475 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
1476 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
1477 if (succOperands.empty())
1482 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1483 brOp.getLoc(), groupName);
1485 auto dstBlockArgRegs =
1486 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
1488 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
1489 auto reg = dstBlockArgRegs[arg.index()];
1492 getState<ComponentLoweringState>().getComponentOp(), reg,
1497 getState<ComponentLoweringState>().addBlockArgGroup(
1498 srcBlock, succBlock.value(), groupOp);
1506 ReturnOp retOp)
const {
1507 if (retOp.getNumOperands() == 0)
1510 std::string groupName =
1511 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
1512 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1513 retOp.getLoc(), groupName);
1514 for (
auto op : enumerate(retOp.getOperands())) {
1515 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
1517 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
1521 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
1527 arith::ConstantOp constOp)
const {
1528 if (isa<IntegerType>(constOp.getType())) {
1537 std::string name = getState<ComponentLoweringState>().getUniqueName(
"cst");
1538 auto floatAttr = cast<FloatAttr>(constOp.getValueAttr());
1540 rewriter.getIntegerType(floatAttr.getType().getIntOrFloatBitWidth());
1541 auto calyxConstOp = rewriter.create<calyx::ConstantOp>(
1542 constOp.getLoc(), name, floatAttr, intType);
1545 rewriter.replaceAllUsesWith(constOp, calyxConstOp.getOut());
1553 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
1557 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
1561 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
1565 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
1569 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
1573 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
1577 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
1581 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
1584 SelectOp op)
const {
1585 return buildLibraryOp<calyx::CombGroupOp, calyx::MuxLibOp>(rewriter, op);
1590 switch (op.getPredicate()) {
1591 case CmpIPredicate::eq:
1592 return buildCmpIOpHelper<calyx::EqLibOp>(rewriter, op);
1593 case CmpIPredicate::ne:
1594 return buildCmpIOpHelper<calyx::NeqLibOp>(rewriter, op);
1595 case CmpIPredicate::uge:
1596 return buildCmpIOpHelper<calyx::GeLibOp>(rewriter, op);
1597 case CmpIPredicate::ult:
1598 return buildCmpIOpHelper<calyx::LtLibOp>(rewriter, op);
1599 case CmpIPredicate::ugt:
1600 return buildCmpIOpHelper<calyx::GtLibOp>(rewriter, op);
1601 case CmpIPredicate::ule:
1602 return buildCmpIOpHelper<calyx::LeLibOp>(rewriter, op);
1603 case CmpIPredicate::sge:
1604 return buildCmpIOpHelper<calyx::SgeLibOp>(rewriter, op);
1605 case CmpIPredicate::slt:
1606 return buildCmpIOpHelper<calyx::SltLibOp>(rewriter, op);
1607 case CmpIPredicate::sgt:
1608 return buildCmpIOpHelper<calyx::SgtLibOp>(rewriter, op);
1609 case CmpIPredicate::sle:
1610 return buildCmpIOpHelper<calyx::SleLibOp>(rewriter, op);
1612 llvm_unreachable(
"unsupported comparison predicate");
1616 TruncIOp op)
const {
1617 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1618 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1622 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1623 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1628 return buildLibraryOp<calyx::CombGroupOp, calyx::ExtSILibOp>(
1629 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1633 IndexCastOp op)
const {
1636 unsigned targetBits = targetType.getIntOrFloatBitWidth();
1637 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
1638 LogicalResult res = success();
1640 if (targetBits == sourceBits) {
1643 op.getResult().replaceAllUsesWith(op.getOperand());
1646 if (sourceBits > targetBits)
1647 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1648 rewriter, op, {sourceType}, {targetType});
1650 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1651 rewriter, op, {sourceType}, {targetType});
1653 rewriter.eraseOp(op);
1660 BitcastOp op)
const {
1661 rewriter.replaceAllUsesWith(op.getOut(), op.getIn());
1666 scf::WhileOp whileOp)
const {
1670 getState<ComponentLoweringState>().addBlockScheduleable(
1676 scf::ForOp forOp)
const {
1682 std::optional<uint64_t> bound = scfForOp.
getBound();
1683 if (!bound.has_value()) {
1685 <<
"Loop bound not statically known. Should "
1686 "transform into while loop using `--scf-for-to-while` before "
1687 "running --lower-scf-to-calyx.";
1689 getState<ComponentLoweringState>().addBlockScheduleable(
1698 scf::IfOp ifOp)
const {
1699 getState<ComponentLoweringState>().addBlockScheduleable(
1705 scf::ReduceOp reduceOp)
const {
1713 scf::ParallelOp parOp)
const {
1716 "AffineParallelUnroll must be run in order to lower scf.parallel");
1719 getState<ComponentLoweringState>().addBlockScheduleable(
1726 scf::ExecuteRegionOp executeRegionOp)
const {
1734 CallOp callOp)
const {
1736 calyx::InstanceOp instanceOp =
1737 getState<ComponentLoweringState>().getInstance(instanceName);
1738 SmallVector<Value, 4> outputPorts;
1739 auto portInfos = instanceOp.getReferencedComponent().getPortInfo();
1740 for (
auto [idx, portInfo] : enumerate(portInfos)) {
1742 outputPorts.push_back(instanceOp.getResult(idx));
1746 for (
auto [idx, result] : llvm::enumerate(callOp.getResults()))
1747 rewriter.replaceAllUsesWith(result, outputPorts[idx]);
1751 getState<ComponentLoweringState>().addBlockScheduleable(
1765 using OpRewritePattern::OpRewritePattern;
1768 PatternRewriter &rewriter)
const override {
1769 if (
auto parOp = dyn_cast_or_null<scf::ParallelOp>(execOp->getParentOp())) {
1770 if (
auto boolAttr = dyn_cast_or_null<mlir::BoolAttr>(
1778 TypeRange yieldTypes = execOp.getResultTypes();
1782 rewriter.setInsertionPointAfter(execOp);
1783 auto *sinkBlock = rewriter.splitBlock(
1785 execOp.getOperation()->getIterator()->getNextNode()->getIterator());
1786 sinkBlock->addArguments(
1788 SmallVector<Location, 4>(yieldTypes.size(), rewriter.getUnknownLoc()));
1789 for (
auto res : enumerate(execOp.getResults()))
1790 res.value().replaceAllUsesWith(sinkBlock->getArgument(res.index()));
1794 make_early_inc_range(execOp.getRegion().getOps<scf::YieldOp>())) {
1795 rewriter.setInsertionPointAfter(yieldOp);
1796 rewriter.replaceOpWithNewOp<BranchOp>(yieldOp, sinkBlock,
1797 yieldOp.getOperands());
1801 auto *preBlock = execOp->getBlock();
1802 auto *execOpEntryBlock = &execOp.getRegion().front();
1803 auto *postBlock = execOp->getBlock()->splitBlock(execOp);
1804 rewriter.inlineRegionBefore(execOp.getRegion(), postBlock);
1805 rewriter.mergeBlocks(postBlock, preBlock);
1806 rewriter.eraseOp(execOp);
1809 rewriter.mergeBlocks(execOpEntryBlock, preBlock);
1817 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1821 PatternRewriter &rewriter)
const override {
1824 DenseMap<Value, unsigned> funcOpArgRewrites;
1828 DenseMap<unsigned, unsigned> funcOpResultMapping;
1836 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
1840 SmallVector<calyx::PortInfo> inPorts, outPorts;
1841 FunctionType funcType = funcOp.getFunctionType();
1842 for (
auto arg : enumerate(funcOp.getArguments())) {
1843 if (!isa<MemRefType>(arg.value().getType())) {
1846 if (
auto portNameAttr = funcOp.getArgAttrOfType<StringAttr>(
1848 inName = portNameAttr.str();
1850 inName =
"in" + std::to_string(arg.index());
1851 funcOpArgRewrites[arg.value()] = inPorts.size();
1853 rewriter.getStringAttr(inName),
1856 DictionaryAttr::get(rewriter.getContext(), {})});
1859 for (
auto res : enumerate(funcType.getResults())) {
1860 std::string resName;
1861 if (
auto portNameAttr = funcOp.getResultAttrOfType<StringAttr>(
1863 resName = portNameAttr.str();
1865 resName =
"out" + std::to_string(res.index());
1866 funcOpResultMapping[res.index()] = outPorts.size();
1869 rewriter.getStringAttr(resName),
1871 DictionaryAttr::get(rewriter.getContext(), {})});
1876 auto ports = inPorts;
1877 llvm::append_range(ports, outPorts);
1881 auto compOp = rewriter.create<calyx::ComponentOp>(
1882 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
1884 std::string funcName =
"func_" + funcOp.getSymName().str();
1885 rewriter.modifyOpInPlace(funcOp, [&]() { funcOp.setSymName(funcName); });
1890 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
1897 unsigned extMemCounter = 0;
1898 for (
auto arg : enumerate(funcOp.getArguments())) {
1899 if (isa<MemRefType>(arg.value().getType())) {
1900 std::string memName =
1901 llvm::join_items(
"_",
"arg_mem", std::to_string(extMemCounter++));
1903 rewriter.setInsertionPointToStart(compOp.getBodyBlock());
1904 MemRefType memtype = cast<MemRefType>(arg.value().getType());
1905 SmallVector<int64_t> addrSizes;
1906 SmallVector<int64_t> sizes;
1907 for (int64_t dim : memtype.getShape()) {
1908 sizes.push_back(dim);
1911 if (sizes.empty() && addrSizes.empty()) {
1913 addrSizes.push_back(1);
1915 auto memOp = rewriter.create<calyx::SeqMemoryOp>(
1916 funcOp.getLoc(), memName,
1917 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1920 compState->registerMemoryInterface(arg.value(),
1926 for (
auto &mapping : funcOpArgRewrites)
1927 mapping.getFirst().replaceAllUsesWith(
1928 compOp.getArgument(mapping.getSecond()));
1939 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1943 PatternRewriter &rewriter)
const override {
1944 LogicalResult res = success();
1945 funcOp.walk([&](Operation *op) {
1947 if (!isa<scf::WhileOp>(op))
1948 return WalkResult::advance();
1950 auto scfWhileOp = cast<scf::WhileOp>(op);
1953 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
1963 enumerate(scfWhileOp.getBefore().front().getArguments())) {
1964 auto condOp = scfWhileOp.getConditionOp().getArgs()[barg.index()];
1965 if (barg.value() != condOp) {
1969 <<
"do-while loops not supported; expected iter-args to "
1970 "remain untransformed in the 'before' region of the "
1972 return WalkResult::interrupt();
1981 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
1982 std::string name = getState<ComponentLoweringState>()
1985 "_arg" + std::to_string(arg.index());
1987 createRegister(arg.value().getLoc(), rewriter,
getComponent(),
1988 arg.value().getType().getIntOrFloatBitWidth(), name);
1989 getState<ComponentLoweringState>().addWhileLoopIterReg(whileOp, reg,
1991 arg.value().replaceAllUsesWith(reg.getOut());
1995 ->getArgument(arg.index())
1996 .replaceAllUsesWith(reg.getOut());
2000 SmallVector<calyx::GroupOp> initGroups;
2001 auto numOperands = whileOp.
getOperation()->getNumOperands();
2002 for (
size_t i = 0; i < numOperands; ++i) {
2004 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
2006 getState<ComponentLoweringState>().getComponentOp(),
2007 getState<ComponentLoweringState>().getUniqueName(
2009 "_init_" + std::to_string(i),
2011 initGroups.push_back(initGroupOp);
2014 getState<ComponentLoweringState>().setWhileLoopInitGroups(whileOp,
2017 return WalkResult::advance();
2027 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2031 PatternRewriter &rewriter)
const override {
2032 LogicalResult res = success();
2033 funcOp.walk([&](Operation *op) {
2035 if (!isa<scf::ForOp>(op))
2036 return WalkResult::advance();
2038 auto scfForOp = cast<scf::ForOp>(op);
2041 getState<ComponentLoweringState>().setUniqueName(forOp.
getOperation(),
2046 auto inductionVar = forOp.
getOperation().getInductionVar();
2047 SmallVector<std::string, 3> inductionVarIdentifiers = {
2048 getState<ComponentLoweringState>()
2051 "induction",
"var"};
2052 std::string name = llvm::join(inductionVarIdentifiers,
"_");
2054 createRegister(inductionVar.getLoc(), rewriter,
getComponent(),
2055 inductionVar.getType().getIntOrFloatBitWidth(), name);
2056 getState<ComponentLoweringState>().addForLoopIterReg(forOp, reg, 0);
2057 inductionVar.replaceAllUsesWith(reg.getOut());
2061 getState<ComponentLoweringState>().getComponentOp();
2062 SmallVector<calyx::GroupOp> initGroups;
2063 SmallVector<std::string, 4> groupIdentifiers = {
2065 getState<ComponentLoweringState>()
2068 "induction",
"var"};
2069 std::string groupName = llvm::join(groupIdentifiers,
"_");
2070 auto groupOp = calyx::createGroup<calyx::GroupOp>(
2072 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp, reg,
2074 initGroups.push_back(groupOp);
2075 getState<ComponentLoweringState>().setForLoopInitGroups(forOp,
2078 return WalkResult::advance();
2085 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2089 PatternRewriter &rewriter)
const override {
2090 LogicalResult res = success();
2091 funcOp.walk([&](Operation *op) {
2092 if (!isa<scf::IfOp>(op))
2093 return WalkResult::advance();
2095 auto scfIfOp = cast<scf::IfOp>(op);
2100 if (scfIfOp.getResults().empty())
2101 return WalkResult::advance();
2104 getState<ComponentLoweringState>().getComponentOp();
2106 std::string thenGroupName =
2107 getState<ComponentLoweringState>().getUniqueName(
"then_br");
2108 auto thenGroupOp = calyx::createGroup<calyx::GroupOp>(
2109 rewriter,
componentOp, scfIfOp.getLoc(), thenGroupName);
2110 getState<ComponentLoweringState>().setThenGroup(scfIfOp, thenGroupOp);
2112 if (!scfIfOp.getElseRegion().empty()) {
2113 std::string elseGroupName =
2114 getState<ComponentLoweringState>().getUniqueName(
"else_br");
2115 auto elseGroupOp = calyx::createGroup<calyx::GroupOp>(
2116 rewriter,
componentOp, scfIfOp.getLoc(), elseGroupName);
2117 getState<ComponentLoweringState>().setElseGroup(scfIfOp, elseGroupOp);
2120 for (
auto ifOpRes : scfIfOp.getResults()) {
2121 auto reg = createRegister(
2123 ifOpRes.getType().getIntOrFloatBitWidth(),
2124 getState<ComponentLoweringState>().getUniqueName(
"if_res"));
2125 getState<ComponentLoweringState>().setResultRegs(
2126 scfIfOp, reg, ifOpRes.getResultNumber());
2129 return WalkResult::advance();
2141 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2145 PatternRewriter &rewriter)
const override {
2146 auto *entryBlock = &funcOp.getBlocks().front();
2147 rewriter.setInsertionPointToStart(
2149 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
2150 DenseSet<Block *> path;
2152 nullptr, entryBlock);
2159 const DenseSet<Block *> &path,
2160 mlir::Block *parentCtrlBlock,
2161 mlir::Block *block)
const {
2162 auto compBlockScheduleables =
2163 getState<ComponentLoweringState>().getBlockScheduleables(block);
2164 auto loc = block->front().getLoc();
2166 if (compBlockScheduleables.size() > 1 &&
2167 !isa<scf::ParallelOp>(block->getParentOp())) {
2168 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
2169 parentCtrlBlock = seqOp.getBodyBlock();
2172 for (
auto &group : compBlockScheduleables) {
2173 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2174 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
2175 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
2176 groupPtr->getSymName());
2177 }
else if (
auto whileSchedPtr = std::get_if<WhileScheduleable>(&group);
2179 auto &whileOp = whileSchedPtr->whileOp;
2183 getState<ComponentLoweringState>().getWhileLoopInitGroups(whileOp),
2185 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
2187 rewriter.create<calyx::SeqOp>(whileOp.getOperation()->getLoc());
2188 auto *whileBodyOpBlock = whileBodyOp.getBodyBlock();
2192 if (LogicalResult result =
2194 whileOp.getBodyBlock());
2199 rewriter.setInsertionPointToEnd(whileBodyOpBlock);
2200 calyx::GroupOp whileLatchGroup =
2201 getState<ComponentLoweringState>().getWhileLoopLatchGroup(whileOp);
2202 rewriter.create<calyx::EnableOp>(whileLatchGroup.getLoc(),
2203 whileLatchGroup.getName());
2204 }
else if (
auto *parSchedPtr = std::get_if<ParScheduleable>(&group)) {
2205 auto parOp = parSchedPtr->parOp;
2206 auto calyxParOp = rewriter.create<calyx::ParOp>(parOp.getLoc());
2208 WalkResult walkResult =
2209 parOp.walk([&](scf::ExecuteRegionOp execRegion) {
2210 rewriter.setInsertionPointToEnd(calyxParOp.getBodyBlock());
2211 auto seqOp = rewriter.create<calyx::SeqOp>(execRegion.getLoc());
2212 rewriter.setInsertionPointToEnd(seqOp.getBodyBlock());
2214 for (
auto &execBlock : execRegion.getRegion().getBlocks()) {
2216 rewriter, path, seqOp.getBodyBlock(), &execBlock);
2218 return WalkResult::interrupt();
2221 return WalkResult::advance();
2224 if (walkResult.wasInterrupted())
2226 }
else if (
auto *forSchedPtr = std::get_if<ForScheduleable>(&group);
2228 auto forOp = forSchedPtr->forOp;
2232 getState<ComponentLoweringState>().getForLoopInitGroups(forOp),
2233 forSchedPtr->bound, rewriter);
2234 rewriter.setInsertionPointToEnd(forCtrlOp.getBodyBlock());
2236 rewriter.create<calyx::SeqOp>(forOp.getOperation()->getLoc());
2237 auto *forBodyOpBlock = forBodyOp.getBodyBlock();
2240 if (LogicalResult res =
buildCFGControl(path, rewriter, forBodyOpBlock,
2241 block, forOp.getBodyBlock());
2246 rewriter.setInsertionPointToEnd(forBodyOpBlock);
2247 calyx::GroupOp forLatchGroup =
2248 getState<ComponentLoweringState>().getForLoopLatchGroup(forOp);
2249 rewriter.create<calyx::EnableOp>(forLatchGroup.getLoc(),
2250 forLatchGroup.getName());
2251 }
else if (
auto *ifSchedPtr = std::get_if<IfScheduleable>(&group);
2253 auto ifOp = ifSchedPtr->ifOp;
2255 Location loc = ifOp->getLoc();
2257 auto cond = ifOp.getCondition();
2259 FlatSymbolRefAttr symbolAttr =
nullptr;
2260 auto condReg = getState<ComponentLoweringState>().getCondReg(ifOp);
2262 auto condGroup = getState<ComponentLoweringState>()
2263 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2265 symbolAttr = FlatSymbolRefAttr::get(
2266 StringAttr::get(getContext(), condGroup.getSymName()));
2269 bool initElse = !ifOp.getElseRegion().empty();
2270 auto ifCtrlOp = rewriter.create<calyx::IfOp>(
2271 loc, cond, symbolAttr, initElse);
2273 rewriter.setInsertionPointToEnd(ifCtrlOp.getBodyBlock());
2276 rewriter.create<calyx::SeqOp>(ifOp.getThenRegion().getLoc());
2277 auto *thenSeqOpBlock = thenSeqOp.getBodyBlock();
2279 auto *thenBlock = &ifOp.getThenRegion().front();
2287 if (!ifOp.getResults().empty()) {
2288 rewriter.setInsertionPointToEnd(thenSeqOpBlock);
2289 calyx::GroupOp thenGroup =
2290 getState<ComponentLoweringState>().getThenGroup(ifOp);
2291 rewriter.create<calyx::EnableOp>(thenGroup.getLoc(),
2292 thenGroup.getName());
2295 if (!ifOp.getElseRegion().empty()) {
2296 rewriter.setInsertionPointToEnd(ifCtrlOp.getElseBody());
2299 rewriter.create<calyx::SeqOp>(ifOp.getElseRegion().getLoc());
2300 auto *elseSeqOpBlock = elseSeqOp.getBodyBlock();
2302 auto *elseBlock = &ifOp.getElseRegion().front();
2308 if (!ifOp.getResults().empty()) {
2309 rewriter.setInsertionPointToEnd(elseSeqOpBlock);
2310 calyx::GroupOp elseGroup =
2311 getState<ComponentLoweringState>().getElseGroup(ifOp);
2312 rewriter.create<calyx::EnableOp>(elseGroup.getLoc(),
2313 elseGroup.getName());
2316 }
else if (
auto *callSchedPtr = std::get_if<CallScheduleable>(&group)) {
2317 auto instanceOp = callSchedPtr->instanceOp;
2318 OpBuilder::InsertionGuard g(rewriter);
2319 auto callBody = rewriter.create<calyx::SeqOp>(instanceOp.getLoc());
2320 rewriter.setInsertionPointToStart(callBody.getBodyBlock());
2322 auto callee = callSchedPtr->callOp.getCallee();
2323 auto *calleeOp = SymbolTable::lookupNearestSymbolFrom(
2324 callSchedPtr->callOp.getOperation()->getParentOp(),
2325 StringAttr::get(rewriter.getContext(),
"func_" + callee.str()));
2326 FuncOp calleeFunc = dyn_cast_or_null<FuncOp>(calleeOp);
2328 auto instanceOpComp =
2329 llvm::cast<calyx::ComponentOp>(instanceOp.getReferencedComponent());
2330 auto *instanceOpLoweringState =
2333 SmallVector<Value, 4> instancePorts;
2334 SmallVector<Value, 4> inputPorts;
2335 SmallVector<Attribute, 4> refCells;
2336 for (
auto operandEnum : enumerate(callSchedPtr->callOp.getOperands())) {
2337 auto operand = operandEnum.value();
2338 auto index = operandEnum.index();
2339 if (!isa<MemRefType>(operand.getType())) {
2340 inputPorts.push_back(operand);
2344 auto memOpName = getState<ComponentLoweringState>()
2345 .getMemoryInterface(operand)
2347 auto memOpNameAttr =
2348 SymbolRefAttr::get(rewriter.getContext(), memOpName);
2349 Value argI = calleeFunc.getArgument(index);
2350 if (isa<MemRefType>(argI.getType())) {
2351 NamedAttrList namedAttrList;
2352 namedAttrList.append(
2353 rewriter.getStringAttr(
2354 instanceOpLoweringState->getMemoryInterface(argI)
2358 DictionaryAttr::get(rewriter.getContext(), namedAttrList));
2361 llvm::copy(instanceOp.getResults().take_front(inputPorts.size()),
2362 std::back_inserter(instancePorts));
2364 ArrayAttr refCellsAttr =
2365 ArrayAttr::get(rewriter.getContext(), refCells);
2367 rewriter.create<calyx::InvokeOp>(
2368 instanceOp.getLoc(), instanceOp.getSymName(), instancePorts,
2369 inputPorts, refCellsAttr, ArrayAttr::get(rewriter.getContext(), {}),
2370 ArrayAttr::get(rewriter.getContext(), {}));
2372 llvm_unreachable(
"Unknown scheduleable");
2383 const DenseSet<Block *> &path, Location loc,
2384 Block *from, Block *to,
2385 Block *parentCtrlBlock)
const {
2388 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2389 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
2390 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
2392 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
2393 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
2399 PatternRewriter &rewriter,
2400 mlir::Block *parentCtrlBlock,
2401 mlir::Block *preBlock,
2402 mlir::Block *block)
const {
2403 if (path.count(block) != 0)
2404 return preBlock->getTerminator()->emitError()
2405 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
2406 "'scf.for' operations.";
2408 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2409 LogicalResult bbSchedResult =
2411 if (bbSchedResult.failed())
2412 return bbSchedResult;
2415 auto successors = block->getSuccessors();
2416 auto nSuccessors = successors.size();
2417 if (nSuccessors > 0) {
2418 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
2420 if (nSuccessors > 1) {
2424 assert(nSuccessors == 2 &&
2425 "only conditional branches supported for now...");
2427 auto cond = brOp->getOperand(0);
2428 auto condGroup = getState<ComponentLoweringState>()
2429 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2430 auto symbolAttr = FlatSymbolRefAttr::get(
2431 StringAttr::get(getContext(), condGroup.getSymName()));
2433 auto ifOp = rewriter.create<calyx::IfOp>(
2434 brOp->getLoc(), cond, symbolAttr,
true);
2435 rewriter.setInsertionPointToStart(ifOp.getThenBody());
2436 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2437 rewriter.setInsertionPointToStart(ifOp.getElseBody());
2438 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2440 bool trueBrSchedSuccess =
2441 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
2442 thenSeqOp.getBodyBlock())
2444 bool falseBrSchedSuccess =
true;
2445 if (trueBrSchedSuccess) {
2446 falseBrSchedSuccess =
2447 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
2448 elseSeqOp.getBodyBlock())
2452 return success(trueBrSchedSuccess && falseBrSchedSuccess);
2455 return schedulePath(rewriter, path, brOp.getLoc(), block,
2456 successors.front(), parentCtrlBlock);
2466 const SmallVector<calyx::GroupOp> &initGroups)
const {
2467 PatternRewriter::InsertionGuard g(rewriter);
2468 auto parOp = rewriter.create<calyx::ParOp>(loc);
2469 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
2470 for (calyx::GroupOp group : initGroups)
2471 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
2475 SmallVector<calyx::GroupOp> initGroups,
2476 PatternRewriter &rewriter)
const {
2477 Location loc = whileOp.
getLoc();
2484 auto condGroup = getState<ComponentLoweringState>()
2485 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2486 auto symbolAttr = FlatSymbolRefAttr::get(
2487 StringAttr::get(getContext(), condGroup.getSymName()));
2488 return rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
2492 SmallVector<calyx::GroupOp>
const &initGroups,
2494 PatternRewriter &rewriter)
const {
2495 Location loc = forOp.
getLoc();
2501 return rewriter.create<calyx::RepeatOp>(loc, bound);
2508 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2511 PatternRewriter &)
const override {
2512 funcOp.walk([&](scf::IfOp op) {
2513 for (
auto res : getState<ComponentLoweringState>().getResultRegs(op))
2514 op.getOperation()->getResults()[res.first].replaceAllUsesWith(
2515 res.second.getOut());
2518 funcOp.walk([&](scf::WhileOp op) {
2527 getState<ComponentLoweringState>().getWhileLoopIterRegs(whileOp))
2528 whileOp.
getOperation()->getResults()[res.first].replaceAllUsesWith(
2529 res.second.getOut());
2532 funcOp.walk([&](memref::LoadOp loadOp) {
2538 loadOp.getResult().replaceAllUsesWith(
2539 getState<ComponentLoweringState>()
2540 .getMemoryInterface(loadOp.getMemref())
2551 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2554 PatternRewriter &rewriter)
const override {
2555 rewriter.eraseOp(funcOp);
2561 PatternRewriter &rewriter)
const override {
55namespace scftocalyx {
…}
2575class SCFToCalyxPass :
public circt::impl::SCFToCalyxBase<SCFToCalyxPass> {
2579 void runOnOperation()
override;
2581 LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp,
2582 std::string &topLevelFunction) {
2583 if (!topLevelFunctionOpt.empty()) {
2584 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
2586 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
2587 <<
"' not found in module.";
2590 topLevelFunction = topLevelFunctionOpt;
2594 auto funcOps = moduleOp.getOps<FuncOp>();
2595 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
2596 topLevelFunction = (*funcOps.begin()).getSymName().str();
2598 moduleOp.emitError()
2599 <<
"Module contains multiple functions, but no top level "
2600 "function was set. Please see --top-level-function";
2605 return createOptNewTopLevelFn(moduleOp, topLevelFunction);
2608 struct LoweringPattern {
2609 enum class Strategy { Once, Greedy };
2618 LogicalResult labelEntryPoint(StringRef topLevelFunction) {
2622 using OpRewritePattern::OpRewritePattern;
2623 LogicalResult matchAndRewrite(mlir::ModuleOp,
2624 PatternRewriter &)
const override {
2629 ConversionTarget target(getContext());
2630 target.addLegalDialect<calyx::CalyxDialect>();
2631 target.addLegalDialect<scf::SCFDialect>();
2632 target.addIllegalDialect<hw::HWDialect>();
2633 target.addIllegalDialect<comb::CombDialect>();
2636 target.addIllegalDialect<FuncDialect>();
2637 target.addIllegalDialect<ArithDialect>();
2638 target.addLegalOp<AddIOp, SelectOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp,
2639 ShRSIOp, AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp,
2640 CondBranchOp, BranchOp, MulIOp, DivUIOp, DivSIOp, RemUIOp,
2641 RemSIOp, ReturnOp, arith::ConstantOp, IndexCastOp,
2642 BitcastOp, FuncOp, ExtSIOp, CallOp, AddFOp, SubFOp,
2643 MulFOp, CmpFOp, FPToSIOp, SIToFPOp, DivFOp>();
2645 RewritePatternSet legalizePatterns(&getContext());
2646 legalizePatterns.add<DummyPattern>(&getContext());
2647 DenseSet<Operation *> legalizedOps;
2648 if (applyPartialConversion(getOperation(), target,
2649 std::move(legalizePatterns))
2660 template <
typename TPattern,
typename... PatternArgs>
2661 void addOncePattern(SmallVectorImpl<LoweringPattern> &
patterns,
2662 PatternArgs &&...args) {
2663 RewritePatternSet ps(&getContext());
2666 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Once});
2669 template <
typename TPattern,
typename... PatternArgs>
2670 void addGreedyPattern(SmallVectorImpl<LoweringPattern> &
patterns,
2671 PatternArgs &&...args) {
2672 RewritePatternSet ps(&getContext());
2673 ps.add<TPattern>(&getContext(), args...);
2675 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Greedy});
2678 LogicalResult runPartialPattern(RewritePatternSet &
pattern,
bool runOnce) {
2680 "Should only apply 1 partial lowering pattern at once");
2686 GreedyRewriteConfig config;
2687 config.enableRegionSimplification =
2688 mlir::GreedySimplifyRegionLevel::Disabled;
2690 config.maxIterations = 1;
2695 (void)applyPatternsGreedily(getOperation(), std::move(
pattern), config);
2704 FuncOp createNewTopLevelFn(ModuleOp moduleOp, std::string &baseName) {
2705 std::string newName =
"main";
2707 if (
auto *existingMainOp = SymbolTable::lookupSymbolIn(moduleOp, newName)) {
2708 auto existingMainFunc = dyn_cast<FuncOp>(existingMainOp);
2709 if (existingMainFunc ==
nullptr) {
2710 moduleOp.emitError() <<
"Symbol 'main' exists but is not a function";
2713 unsigned counter = 0;
2714 std::string newOldName = baseName;
2715 while (SymbolTable::lookupSymbolIn(moduleOp, newOldName))
2716 newOldName = llvm::join_items(
"_", baseName, std::to_string(++counter));
2717 existingMainFunc.setName(newOldName);
2718 if (baseName ==
"main")
2719 baseName = newOldName;
2723 OpBuilder builder(moduleOp.getContext());
2724 builder.setInsertionPointToStart(moduleOp.getBody());
2726 FunctionType funcType = builder.getFunctionType({}, {});
2729 builder.create<FuncOp>(moduleOp.getLoc(), newName, funcType))
2739 void insertCallFromNewTopLevel(OpBuilder &builder, FuncOp caller,
2741 if (caller.getBody().empty()) {
2742 caller.addEntryBlock();
2745 Block *callerEntryBlock = &caller.getBody().front();
2746 builder.setInsertionPointToStart(callerEntryBlock);
2750 SmallVector<Type, 4> nonMemRefCalleeArgTypes;
2751 for (
auto arg : callee.getArguments()) {
2752 if (!isa<MemRefType>(arg.getType())) {
2753 nonMemRefCalleeArgTypes.push_back(arg.getType());
2757 for (Type type : nonMemRefCalleeArgTypes) {
2758 callerEntryBlock->addArgument(type, caller.getLoc());
2761 FunctionType callerFnType = caller.getFunctionType();
2762 SmallVector<Type, 4> updatedCallerArgTypes(
2763 caller.getFunctionType().getInputs());
2764 updatedCallerArgTypes.append(nonMemRefCalleeArgTypes.begin(),
2765 nonMemRefCalleeArgTypes.end());
2766 caller.setType(FunctionType::get(caller.getContext(), updatedCallerArgTypes,
2767 callerFnType.getResults()));
2769 Block *calleeFnBody = &callee.getBody().front();
2770 unsigned originalCalleeArgNum = callee.getArguments().size();
2772 SmallVector<Value, 4> extraMemRefArgs;
2773 SmallVector<Type, 4> extraMemRefArgTypes;
2774 SmallVector<Value, 4> extraMemRefOperands;
2775 SmallVector<Operation *, 4> opsToModify;
2776 for (
auto &op : callee.getBody().getOps()) {
2777 if (isa<memref::AllocaOp, memref::AllocOp, memref::GetGlobalOp>(op))
2778 opsToModify.push_back(&op);
2783 builder.setInsertionPointToEnd(callerEntryBlock);
2784 for (
auto *op : opsToModify) {
2787 TypeSwitch<Operation *>(op)
2788 .Case<memref::AllocaOp>([&](memref::AllocaOp allocaOp) {
2789 newOpRes = builder.create<memref::AllocaOp>(callee.getLoc(),
2790 allocaOp.getType());
2792 .Case<memref::AllocOp>([&](memref::AllocOp allocOp) {
2793 newOpRes = builder.create<memref::AllocOp>(callee.getLoc(),
2796 .Case<memref::GetGlobalOp>([&](memref::GetGlobalOp getGlobalOp) {
2797 newOpRes = builder.create<memref::GetGlobalOp>(
2798 caller.getLoc(), getGlobalOp.getType(), getGlobalOp.getName());
2800 .Default([&](Operation *defaultOp) {
2801 llvm::report_fatal_error(
"Unsupported operation in TypeSwitch");
2803 extraMemRefOperands.push_back(newOpRes);
2805 calleeFnBody->addArgument(newOpRes.getType(), callee.getLoc());
2806 BlockArgument newBodyArg = calleeFnBody->getArguments().back();
2807 op->getResult(0).replaceAllUsesWith(newBodyArg);
2809 extraMemRefArgs.push_back(newBodyArg);
2810 extraMemRefArgTypes.push_back(newBodyArg.getType());
2813 SmallVector<Type, 4> updatedCalleeArgTypes(
2814 callee.getFunctionType().getInputs());
2815 updatedCalleeArgTypes.append(extraMemRefArgTypes.begin(),
2816 extraMemRefArgTypes.end());
2817 callee.setType(FunctionType::get(callee.getContext(), updatedCalleeArgTypes,
2818 callee.getFunctionType().getResults()));
2820 unsigned otherArgsCount = 0;
2821 SmallVector<Value, 4> calleeArgFnOperands;
2822 builder.setInsertionPointToStart(callerEntryBlock);
2823 for (
auto arg : callee.getArguments().take_front(originalCalleeArgNum)) {
2824 if (isa<MemRefType>(arg.getType())) {
2825 auto memrefType = cast<MemRefType>(arg.getType());
2827 builder.create<memref::AllocOp>(callee.getLoc(), memrefType);
2828 calleeArgFnOperands.push_back(allocOp);
2830 auto callerArg = callerEntryBlock->getArgument(otherArgsCount++);
2831 calleeArgFnOperands.push_back(callerArg);
2835 SmallVector<Value, 4> fnOperands;
2836 fnOperands.append(calleeArgFnOperands.begin(), calleeArgFnOperands.end());
2837 fnOperands.append(extraMemRefOperands.begin(), extraMemRefOperands.end());
2839 SymbolRefAttr::get(builder.getContext(), callee.getSymName());
2840 auto resultTypes = callee.getResultTypes();
2842 builder.setInsertionPointToEnd(callerEntryBlock);
2843 builder.create<CallOp>(caller.getLoc(), calleeName, resultTypes,
2845 builder.create<ReturnOp>(caller.getLoc());
2851 LogicalResult createOptNewTopLevelFn(ModuleOp moduleOp,
2852 std::string &topLevelFunction) {
2853 auto hasMemrefArguments = [](FuncOp func) {
2855 func.getArguments().begin(), func.getArguments().end(),
2856 [](BlockArgument arg) { return isa<MemRefType>(arg.getType()); });
2862 auto funcOps = moduleOp.getOps<FuncOp>();
2863 bool hasMemrefArgsInTopLevel =
2864 std::any_of(funcOps.begin(), funcOps.end(), [&](
auto funcOp) {
2865 return funcOp.getName() == topLevelFunction &&
2866 hasMemrefArguments(funcOp);
2869 if (hasMemrefArgsInTopLevel) {
2870 auto newTopLevelFunc = createNewTopLevelFn(moduleOp, topLevelFunction);
2871 if (!newTopLevelFunc)
2874 OpBuilder builder(moduleOp.getContext());
2875 Operation *oldTopLevelFuncOp =
2876 SymbolTable::lookupSymbolIn(moduleOp, topLevelFunction);
2877 if (
auto oldTopLevelFunc = dyn_cast<FuncOp>(oldTopLevelFuncOp))
2878 insertCallFromNewTopLevel(builder, newTopLevelFunc, oldTopLevelFunc);
2880 moduleOp.emitOpError(
"Original top-level function not found!");
2883 topLevelFunction =
"main";
2890void SCFToCalyxPass::runOnOperation() {
2895 std::string topLevelFunction;
2896 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
2897 signalPassFailure();
2902 if (failed(labelEntryPoint(topLevelFunction))) {
2903 signalPassFailure();
2906 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
2917 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
2918 SmallVector<LoweringPattern, 8> loweringPatterns;
2922 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
2926 addGreedyPattern<InlineExecuteRegionOpPattern>(loweringPatterns);
2929 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
2933 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
2936 addOncePattern<calyx::BuildCallInstance>(loweringPatterns, patternState,
2940 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
2946 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
2952 addOncePattern<BuildForGroups>(loweringPatterns, patternState, funcMap,
2955 addOncePattern<BuildIfGroups>(loweringPatterns, patternState, funcMap,
2965 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
2971 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
2976 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
2981 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
2987 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
2991 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
2996 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
3000 for (
auto &pat : loweringPatterns) {
3003 pat.strategy == LoweringPattern::Strategy::Once);
3006 signalPassFailure();
3013 RewritePatternSet cleanupPatterns(&getContext());
3017 applyPatternsGreedily(getOperation(), std::move(cleanupPatterns)))) {
3018 signalPassFailure();
3022 if (ciderSourceLocationMetadata) {
3025 SmallVector<Attribute, 16> sourceLocations;
3026 getOperation()->walk([&](calyx::ComponentOp component) {
3030 MLIRContext *context = getOperation()->getContext();
3031 getOperation()->setAttr(
"calyx.metadata",
3032 ArrayAttr::get(context, sourceLocations));
3042 return std::make_unique<SCFToCalyxPass>();
assert(baseType &&"element must be base type")
static Block * getBodyBlock(FModuleLike mod)
RewritePatternSet pattern
std::shared_ptr< calyx::CalyxLoweringState > loweringState
LogicalResult partialPatternRes
An interface for conversion passes that lower Calyx programs.
std::string irName(ValueOrBlock &v)
Returns a meaningful name for a value within the program scope.
std::string blockName(Block *b)
Returns a meaningful name for a block within the program scope (removes the ^ prefix from block names...
StringRef getTopLevelFunction() const
Returns the name of the top-level function in the source program.
T * getState(calyx::ComponentOp op)
Returns the component lowering state associated with op.
void setFuncOpResultMapping(const DenseMap< unsigned, unsigned > &mapping)
Assign a mapping between the source funcOp result indices and the corresponding output port indices o...
std::string getUniqueName(StringRef prefix)
Returns a unique name within compOp with the provided prefix.
calyx::ComponentOp component
The component which this lowering state is associated to.
void registerMemoryInterface(Value memref, const calyx::MemoryInterface &memoryInterface)
Registers a memory interface as being associated with a memory identified by 'memref'.
calyx::ComponentOp getComponentOp()
Returns the calyx::ComponentOp associated with this lowering state.
void setDataField(StringRef name, llvm::json::Array data)
ComponentLoweringStateInterface(calyx::ComponentOp component)
void setFormat(StringRef name, std::string numType, bool isSigned, unsigned width)
FuncOpPartialLoweringPatterns are patterns which intend to match on FuncOps and then perform their ow...
calyx::ComponentOp getComponent() const
Returns the component operation associated with the currently executing partial lowering.
DenseMap< mlir::func::FuncOp, calyx::ComponentOp > & functionMapping
CalyxLoweringState & loweringState() const
Return the calyx lowering state for this pattern.
FuncOpPartialLoweringPattern(MLIRContext *context, LogicalResult &resRef, PatternApplicationState &patternState, DenseMap< mlir::func::FuncOp, calyx::ComponentOp > &map, calyx::CalyxLoweringState &state)
calyx::GroupOp getLoopLatchGroup(ScfWhileOp op)
Retrieve the loop latch group registered for op.
void setLoopLatchGroup(ScfWhileOp op, calyx::GroupOp group)
Registers grp to be the loop latch group of op.
calyx::RegisterOp getLoopIterReg(ScfForOp op, unsigned idx)
Return a mapping of block argument indices to block argument.
void addLoopIterReg(ScfWhileOp op, calyx::RegisterOp reg, unsigned idx)
Register reg as being the idx'th iter_args register for 'op'.
void setLoopInitGroups(ScfWhileOp op, SmallVector< calyx::GroupOp > groups)
Registers groups to be the loop init groups of op.
SmallVector< calyx::GroupOp > getLoopInitGroups(ScfWhileOp op)
Retrieve the loop init groups registered for op.
calyx::GroupOp buildLoopIterArgAssignments(OpBuilder &builder, ScfWhileOp op, calyx::ComponentOp componentOp, Twine uniqueSuffix, MutableArrayRef< OpOperand > ops)
Creates a new group that assigns the 'ops' values to the iter arg registers of the loop operation.
const DenseMap< unsigned, calyx::RegisterOp > & getLoopIterRegs(ScfWhileOp op)
Return a mapping of block argument indices to block argument.
PatternApplicationState & patternState
scf::ForOp getOperation()
Location getLoc() override
RepeatOpInterface(scf::ForOp op)
Holds common utilities used for scheduling when lowering to Calyx.
scf::WhileOp getOperation()
WhileOpInterface(scf::WhileOp op)
Location getLoc() override
Builds a control schedule by traversing the CFG of the function and associating this with the previou...
calyx::RepeatOp buildForCtrlOp(ScfForOp forOp, SmallVector< calyx::GroupOp > const &initGroups, uint64_t bound, PatternRewriter &rewriter) const
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
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 ...
calyx::WhileOp buildWhileCtrlOp(ScfWhileOp whileOp, SmallVector< calyx::GroupOp > initGroups, PatternRewriter &rewriter) const
LogicalResult scheduleBasicBlock(PatternRewriter &rewriter, const DenseSet< Block * > &path, mlir::Block *parentCtrlBlock, mlir::Block *block) const
Sequentially schedules the groups that registered themselves with 'block'.
LogicalResult buildCFGControl(DenseSet< Block * > path, PatternRewriter &rewriter, mlir::Block *parentCtrlBlock, mlir::Block *preBlock, mlir::Block *block) const
void insertParInitGroups(PatternRewriter &rewriter, Location loc, const SmallVector< calyx::GroupOp > &initGroups) const
In BuildForGroups, a register is created for the iteration argument of the for op.
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
Iterate through the operations of a source function and instantiate components or primitives based on...
BuildOpGroups(MLIRContext *context, LogicalResult &resRef, calyx::PatternApplicationState &patternState, DenseMap< mlir::func::FuncOp, calyx::ComponentOp > &map, calyx::CalyxLoweringState &state, mlir::Pass::Option< std::string > &writeJsonOpt)
LogicalResult buildCmpIOpHelper(PatternRewriter &rewriter, CmpIOp op) const
void setupCmpIOp(PatternRewriter &rewriter, CmpIOp cmpIOp, Operation *group, calyx::RegisterOp &condReg, calyx::RegisterOp &resReg, TCalyxLibOp calyxOp) const
LogicalResult buildFpIntTypeCastOp(PatternRewriter &rewriter, TSrcOp op, unsigned inputWidth, unsigned outputWidth, StringRef signedPort) const
TGroupOp createGroupForOp(PatternRewriter &rewriter, Operation *op) const
Creates a group named by the basic block which the input op resides in.
LogicalResult buildLibraryOp(PatternRewriter &rewriter, TSrcOp op) const
buildLibraryOp which provides in- and output types based on the operands and results of the op argume...
LogicalResult buildOp(PatternRewriter &rewriter, scf::YieldOp yieldOp) const
Op builder specializations.
calyx::RegisterOp createSignalRegister(PatternRewriter &rewriter, Value signal, bool invert, StringRef nameSuffix, calyx::CompareFOpIEEE754 calyxCmpFOp, calyx::GroupOp group) const
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 partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult buildLibraryBinaryPipeOp(PatternRewriter &rewriter, TSrcOp op, TOpType opPipe, Value out) const
buildLibraryBinaryPipeOp will build a TCalyxLibBinaryPipeOp, to deal with MulIOp, DivUIOp and RemUIOp...
mlir::Pass::Option< std::string > & writeJson
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)
void setForLoopInitGroups(ScfForOp op, SmallVector< calyx::GroupOp > groups)
calyx::GroupOp buildForLoopIterArgAssignments(OpBuilder &builder, ScfForOp op, calyx::ComponentOp componentOp, Twine uniqueSuffix, MutableArrayRef< OpOperand > ops)
void setForLoopLatchGroup(ScfForOp op, calyx::GroupOp group)
SmallVector< calyx::GroupOp > getForLoopInitGroups(ScfForOp op)
void addForLoopIterReg(ScfForOp op, calyx::RegisterOp reg, unsigned idx)
calyx::GroupOp getForLoopLatchGroup(ScfForOp op)
calyx::RegisterOp getForLoopIterReg(ScfForOp op, unsigned idx)
const DenseMap< unsigned, calyx::RegisterOp > & getForLoopIterRegs(ScfForOp op)
DenseMap< Operation *, calyx::GroupOp > elseGroup
DenseMap< Operation *, calyx::GroupOp > thenGroup
void setCondReg(scf::IfOp op, calyx::RegisterOp regOp)
const DenseMap< unsigned, calyx::RegisterOp > & getResultRegs(scf::IfOp op)
void setElseGroup(scf::IfOp op, calyx::GroupOp group)
void setResultRegs(scf::IfOp op, calyx::RegisterOp reg, unsigned idx)
void setThenGroup(scf::IfOp op, calyx::GroupOp group)
DenseMap< Operation *, DenseMap< unsigned, calyx::RegisterOp > > resultRegs
calyx::RegisterOp getResultRegs(scf::IfOp op, unsigned idx)
calyx::RegisterOp getCondReg(scf::IfOp op)
calyx::GroupOp getThenGroup(scf::IfOp op)
DenseMap< Operation *, calyx::RegisterOp > condReg
calyx::GroupOp getElseGroup(scf::IfOp op)
Inlines Calyx ExecuteRegionOp operations within their parent blocks.
LogicalResult matchAndRewrite(scf::ExecuteRegionOp execOp, PatternRewriter &rewriter) const override
LateSSAReplacement contains various functions for replacing SSA values that were not replaced during ...
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &) const override
std::optional< int64_t > getBound() override
Block::BlockArgListType getBodyArgs() override
Block * getBodyBlock() override
Block * getBodyBlock() override
ScfWhileOp(scf::WhileOp op)
Block::BlockArgListType getBodyArgs() override
Value getConditionValue() override
std::optional< int64_t > getBound() override
Block * getConditionBlock() override
Stores the state information for condition checks involving sequential computation.
void setSeqResReg(Operation *op, calyx::RegisterOp reg)
calyx::RegisterOp getSeqResReg(Operation *op)
DenseMap< Operation *, calyx::RegisterOp > resultRegs
calyx::GroupOp buildWhileLoopIterArgAssignments(OpBuilder &builder, ScfWhileOp op, calyx::ComponentOp componentOp, Twine uniqueSuffix, MutableArrayRef< OpOperand > ops)
void setWhileLoopInitGroups(ScfWhileOp op, SmallVector< calyx::GroupOp > groups)
SmallVector< calyx::GroupOp > getWhileLoopInitGroups(ScfWhileOp op)
void addWhileLoopIterReg(ScfWhileOp op, calyx::RegisterOp reg, unsigned idx)
void setWhileLoopLatchGroup(ScfWhileOp op, calyx::GroupOp group)
const DenseMap< unsigned, calyx::RegisterOp > & getWhileLoopIterRegs(ScfWhileOp op)
calyx::GroupOp getWhileLoopLatchGroup(ScfWhileOp op)
bool parentIsSeqCell(Value value)
void addMandatoryComponentPorts(PatternRewriter &rewriter, SmallVectorImpl< calyx::PortInfo > &ports)
void buildAssignmentsForRegisterWrite(OpBuilder &builder, calyx::GroupOp groupOp, calyx::ComponentOp componentOp, calyx::RegisterOp ®, Value inputValue)
Creates register assignment operations within the provided groupOp.
DenseMap< const mlir::RewritePattern *, SmallPtrSet< Operation *, 16 > > PatternApplicationState
Extra state that is passed to all PartialLoweringPatterns so they can record when they have run on an...
PredicateInfo getPredicateInfo(mlir::arith::CmpFPredicate pred)
Type normalizeType(OpBuilder &builder, Type type)
LogicalResult applyModuleOpConversion(mlir::ModuleOp, StringRef topLevelFunction)
Helper to update the top-level ModuleOp to set the entrypoing function.
WalkResult getCiderSourceLocationMetadata(calyx::ComponentOp component, SmallVectorImpl< Attribute > &sourceLocations)
bool matchConstantOp(Operation *op, APInt &value)
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.
bool noStoresToMemory(Value memoryReference)
bool singleLoadFromMemory(Value memoryReference)
Type toBitVector(T type)
Performs a bit cast from a non-signless integer type value, such as a floating point value,...
std::string getInstanceName(mlir::func::CallOp callOp)
A helper function to get the instance name.
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
static constexpr std::string_view sPortNameAttr
static constexpr std::string_view unrolledParallelAttr
static LogicalResult buildAllocOp(ComponentLoweringState &componentState, PatternRewriter &rewriter, TAllocOp allocOp)
std::variant< calyx::GroupOp, WhileScheduleable, ForScheduleable, IfScheduleable, CallScheduleable, ParScheduleable > Scheduleable
A variant of types representing scheduleable operations.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< OperationPass< ModuleOp > > createSCFToCalyxPass()
Create an SCF to Calyx conversion pass.
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.
Predicate information for the floating point comparisons.
calyx::InstanceOp instanceOp
Instance for invoking.
ScfForOp forOp
For operation to schedule.
Creates a new Calyx component for each FuncOp in the program.
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
scf::ParallelOp parOp
Parallel operation to schedule.
ScfWhileOp whileOp
While operation to schedule.