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/Math/IR/Math.h"
25#include "mlir/Dialect/MemRef/IR/MemRef.h"
26#include "mlir/Dialect/SCF/IR/SCF.h"
27#include "mlir/IR/AsmState.h"
28#include "mlir/IR/Matchers.h"
29#include "mlir/Pass/Pass.h"
30#include "mlir/Support/LogicalResult.h"
31#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
32#include "llvm/ADT/TypeSwitch.h"
33#include "llvm/Support/LogicalResult.h"
34#include "llvm/Support/raw_os_ostream.h"
35#include "llvm/Support/raw_ostream.h"
45#define GEN_PASS_DEF_SCFTOCALYX
46#include "circt/Conversion/Passes.h.inc"
51using namespace mlir::arith;
52using namespace mlir::cf;
55class ComponentLoweringStateInterface;
83 std::optional<int64_t>
getBound()
override {
return std::nullopt; }
145 Operation *operation = op.getOperation();
146 [[maybe_unused]]
auto [it, succeeded] =
147 condReg.insert(std::make_pair(operation, regOp));
149 "A condition register was already set for this scf::IfOp!");
153 auto it =
condReg.find(op.getOperation());
160 Operation *operation = op.getOperation();
162 "A then group was already set for this scf::IfOp!\n");
167 auto it =
thenGroup.find(op.getOperation());
169 "No then group was set for this scf::IfOp!\n");
174 Operation *operation = op.getOperation();
176 "An else group was already set for this scf::IfOp!\n");
181 auto it =
elseGroup.find(op.getOperation());
183 "No else group was set for this scf::IfOp!\n");
189 "A register was already registered for the given yield result.\n");
190 assert(idx < op->getNumOperands());
200 auto it = regs.find(idx);
201 assert(it != regs.end() &&
"resultReg not found");
207 DenseMap<Operation *, calyx::RegisterOp>
condReg;
210 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
resultRegs;
220 OpBuilder &builder,
ScfWhileOp op, calyx::ComponentOp componentOp,
221 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
228 const DenseMap<unsigned, calyx::RegisterOp> &
239 SmallVector<calyx::GroupOp> groups) {
251 OpBuilder &builder,
ScfForOp op, calyx::ComponentOp componentOp,
252 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
281 [[maybe_unused]]
auto cellOp = dyn_cast<calyx::CellInterface>(op);
282 assert(cellOp && !cellOp.isCombinational());
283 [[maybe_unused]]
auto [it, succeeded] =
286 "A register was already set for this sequential operation!");
292 "No register was set for this sequential operation!");
326 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
328 mlir::Pass::Option<std::string> &writeJsonOpt)
331 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
335 PatternRewriter &rewriter)
const override {
338 bool opBuiltSuccessfully =
true;
339 funcOp.walk([&](Operation *_op) {
340 opBuiltSuccessfully &=
341 TypeSwitch<mlir::Operation *, bool>(_op)
342 .template Case<arith::ConstantOp, ReturnOp, BranchOpInterface,
344 scf::YieldOp, scf::WhileOp, scf::ForOp, scf::IfOp,
345 scf::ParallelOp, scf::ReduceOp,
346 scf::ExecuteRegionOp,
348 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
349 memref::StoreOp, memref::GetGlobalOp,
351 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp,
352 AndIOp, XOrIOp, OrIOp, ExtUIOp, ExtSIOp, TruncIOp,
353 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp,
355 AddFOp, SubFOp, MulFOp, CmpFOp, FPToSIOp, SIToFPOp,
356 DivFOp, math::SqrtOp, math::AbsFOp,
358 SelectOp, IndexCastOp, BitcastOp, CallOp>(
359 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
360 .
template Case<FuncOp, scf::ConditionOp>([&](
auto) {
364 .Default([&](
auto op) {
365 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
369 return opBuiltSuccessfully ? WalkResult::advance()
370 : WalkResult::interrupt();
374 auto &extMemData = getState<ComponentLoweringState>().getExtMemData();
375 if (extMemData.getAsObject()->empty())
378 if (
auto fileLoc = dyn_cast<mlir::FileLineColLoc>(funcOp->getLoc())) {
379 std::string filename = fileLoc.getFilename().str();
380 std::filesystem::path path(filename);
381 std::string jsonFileName =
writeJson.getValue() +
".json";
382 auto outFileName = path.parent_path().append(jsonFileName);
383 std::ofstream outFile(outFileName);
385 if (!outFile.is_open()) {
386 llvm::errs() <<
"Unable to open file: " << outFileName.string()
390 llvm::raw_os_ostream llvmOut(outFile);
391 llvm::json::OStream jsonOS(llvmOut, 2);
392 jsonOS.value(extMemData);
398 return success(opBuiltSuccessfully);
404 LogicalResult
buildOp(PatternRewriter &rewriter, scf::YieldOp yieldOp)
const;
405 LogicalResult
buildOp(PatternRewriter &rewriter,
406 BranchOpInterface brOp)
const;
407 LogicalResult
buildOp(PatternRewriter &rewriter,
408 arith::ConstantOp constOp)
const;
409 LogicalResult
buildOp(PatternRewriter &rewriter, SelectOp op)
const;
410 LogicalResult
buildOp(PatternRewriter &rewriter, AddIOp op)
const;
411 LogicalResult
buildOp(PatternRewriter &rewriter, SubIOp op)
const;
412 LogicalResult
buildOp(PatternRewriter &rewriter, MulIOp op)
const;
413 LogicalResult
buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
414 LogicalResult
buildOp(PatternRewriter &rewriter, DivSIOp op)
const;
415 LogicalResult
buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
416 LogicalResult
buildOp(PatternRewriter &rewriter, RemSIOp op)
const;
417 LogicalResult
buildOp(PatternRewriter &rewriter, AddFOp op)
const;
418 LogicalResult
buildOp(PatternRewriter &rewriter, SubFOp op)
const;
419 LogicalResult
buildOp(PatternRewriter &rewriter, MulFOp op)
const;
420 LogicalResult
buildOp(PatternRewriter &rewriter, CmpFOp op)
const;
421 LogicalResult
buildOp(PatternRewriter &rewriter, FPToSIOp op)
const;
422 LogicalResult
buildOp(PatternRewriter &rewriter, SIToFPOp op)
const;
423 LogicalResult
buildOp(PatternRewriter &rewriter, DivFOp op)
const;
424 LogicalResult
buildOp(PatternRewriter &rewriter, math::SqrtOp op)
const;
425 LogicalResult
buildOp(PatternRewriter &rewriter, math::AbsFOp op)
const;
426 LogicalResult
buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
427 LogicalResult
buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
428 LogicalResult
buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
429 LogicalResult
buildOp(PatternRewriter &rewriter, AndIOp op)
const;
430 LogicalResult
buildOp(PatternRewriter &rewriter, OrIOp op)
const;
431 LogicalResult
buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
432 LogicalResult
buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
433 LogicalResult
buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
434 LogicalResult
buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
435 LogicalResult
buildOp(PatternRewriter &rewriter, ExtSIOp op)
const;
436 LogicalResult
buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
437 LogicalResult
buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
438 LogicalResult
buildOp(PatternRewriter &rewriter, BitcastOp op)
const;
439 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
440 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
441 LogicalResult
buildOp(PatternRewriter &rewriter,
442 memref::GetGlobalOp op)
const;
443 LogicalResult
buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
444 LogicalResult
buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
445 LogicalResult
buildOp(PatternRewriter &rewriter, scf::WhileOp whileOp)
const;
446 LogicalResult
buildOp(PatternRewriter &rewriter, scf::ForOp forOp)
const;
447 LogicalResult
buildOp(PatternRewriter &rewriter, scf::IfOp ifOp)
const;
448 LogicalResult
buildOp(PatternRewriter &rewriter,
449 scf::ReduceOp reduceOp)
const;
450 LogicalResult
buildOp(PatternRewriter &rewriter,
451 scf::ParallelOp parallelOp)
const;
452 LogicalResult
buildOp(PatternRewriter &rewriter,
453 scf::ExecuteRegionOp executeRegionOp)
const;
454 LogicalResult
buildOp(PatternRewriter &rewriter, CallOp callOp)
const;
459 template <
typename TCalyxLibOp>
460 void setupCmpIOp(PatternRewriter &rewriter, CmpIOp cmpIOp, Operation *group,
461 calyx::RegisterOp &condReg, calyx::RegisterOp &resReg,
462 TCalyxLibOp calyxOp)
const {
466 StringRef opName = cmpIOp.getOperationName().split(
".").second;
467 Type width = cmpIOp.getResult().getType();
469 condReg = createRegister(
471 width.getIntOrFloatBitWidth(),
472 getState<ComponentLoweringState>().getUniqueName(opName));
474 for (
auto *user : cmpIOp->getUsers()) {
475 if (
auto ifOp = dyn_cast<scf::IfOp>(user))
476 getState<ComponentLoweringState>().setCondReg(ifOp, condReg);
480 lhsIsSeqOp != rhsIsSeqOp &&
481 "unexpected sequential operation on both sides; please open an issue");
485 cast<calyx::RegisterOp>(lhsIsSeqOp ? cmpIOp.getLhs().getDefiningOp()
486 : cmpIOp.getRhs().getDefiningOp());
488 auto groupOp = cast<calyx::GroupOp>(group);
489 getState<ComponentLoweringState>().addBlockScheduleable(cmpIOp->getBlock(),
492 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
493 auto loc = cmpIOp.getLoc();
495 (isa<calyx::EqLibOp, calyx::NeqLibOp, calyx::SleLibOp, calyx::SltLibOp,
496 calyx::LeLibOp, calyx::LtLibOp, calyx::GeLibOp, calyx::GtLibOp,
497 calyx::SgeLibOp, calyx::SgtLibOp>(calyxOp.getOperation())) &&
498 "Must be a Calyx comparison library operation.");
499 int64_t outputIndex = 2;
500 calyx::AssignOp::create(rewriter, loc, condReg.getIn(),
501 calyxOp.getResult(outputIndex));
502 calyx::AssignOp::create(
503 rewriter, loc, condReg.getWriteEn(),
504 createConstant(loc, rewriter,
505 getState<ComponentLoweringState>().getComponentOp(), 1,
507 calyx::GroupDoneOp::create(rewriter, loc, condReg.getDone());
509 getState<ComponentLoweringState>().addSeqGuardCmpLibOp(cmpIOp);
460 void setupCmpIOp(PatternRewriter &rewriter, CmpIOp cmpIOp, Operation *group, {
…}
512 template <
typename CmpILibOp>
514 bool isIfOpGuard = std::any_of(op->getUsers().begin(), op->getUsers().end(),
515 [](
auto op) { return isa<scf::IfOp>(op); });
520 return buildLibraryOp<calyx::GroupOp, CmpILibOp>(rewriter, op);
521 return buildLibraryOp<calyx::CombGroupOp, CmpILibOp>(rewriter, op);
526 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
528 TypeRange srcTypes, TypeRange dstTypes)
const {
529 SmallVector<Type> types;
530 for (Type srcType : srcTypes)
532 for (Type dstType : dstTypes)
536 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
537 rewriter, op.getLoc(), types);
539 auto directions = calyxOp.portDirections();
540 SmallVector<Value, 4> opInputPorts;
541 SmallVector<Value, 4> opOutputPorts;
542 for (
auto dir : enumerate(directions)) {
544 opInputPorts.push_back(calyxOp.getResult(dir.index()));
546 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
549 opInputPorts.size() == op->getNumOperands() &&
550 opOutputPorts.size() == op->getNumResults() &&
551 "Expected an equal number of in/out ports in the Calyx library op with "
552 "respect to the number of operands/results of the source operation.");
555 auto group = createGroupForOp<TGroupOp>(rewriter, op);
557 bool isSeqCondCheck = isa<calyx::GroupOp>(group);
558 calyx::RegisterOp condReg =
nullptr, resReg =
nullptr;
559 if (isa<CmpIOp>(op) && isSeqCondCheck) {
560 auto cmpIOp = cast<CmpIOp>(op);
561 setupCmpIOp(rewriter, cmpIOp, group, condReg, resReg, calyxOp);
564 rewriter.setInsertionPointToEnd(group.getBodyBlock());
566 for (
auto dstOp : enumerate(opInputPorts)) {
569 : op->getOperand(dstOp.index());
570 calyx::AssignOp::create(rewriter, op.getLoc(), dstOp.value(), srcOp);
574 for (
auto res : enumerate(opOutputPorts)) {
575 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
577 auto dstOp = isSeqCondCheck ? condReg.getOut() : res.value();
578 op->getResult(res.index()).replaceAllUsesWith(dstOp);
586 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
588 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
589 rewriter, op, op.getOperandTypes(), op->getResultTypes());
593 template <
typename TGroupOp>
595 Block *block = op->getBlock();
596 auto groupName = getState<ComponentLoweringState>().getUniqueName(
598 return calyx::createGroup<TGroupOp>(
599 rewriter, getState<ComponentLoweringState>().getComponentOp(),
600 op->getLoc(), groupName);
605 template <
typename TOpType,
typename TSrcOp>
607 TOpType opPipe, Value out)
const {
608 StringRef opName = TSrcOp::getOperationName().split(
".").second;
609 Location loc = op.getLoc();
610 Type width = op.getResult().getType();
611 auto reg = createRegister(
612 op.getLoc(), rewriter,
getComponent(), width.getIntOrFloatBitWidth(),
613 getState<ComponentLoweringState>().getUniqueName(opName));
616 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
617 OpBuilder builder(group->getRegion(0));
618 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
621 rewriter.setInsertionPointToEnd(group.getBodyBlock());
622 if constexpr (std::is_same_v<TSrcOp, math::SqrtOp>)
625 calyx::AssignOp::create(rewriter, loc, opPipe.getLeft(), op.getOperand());
627 calyx::AssignOp::create(rewriter, loc, opPipe.getLeft(), op.getLhs());
628 calyx::AssignOp::create(rewriter, loc, opPipe.getRight(), op.getRhs());
631 calyx::AssignOp::create(rewriter, loc, reg.getIn(), out);
633 calyx::AssignOp::create(rewriter, loc, reg.getWriteEn(), opPipe.getDone());
638 calyx::AssignOp::create(
639 rewriter, loc, opPipe.getGo(), c1,
642 calyx::GroupDoneOp::create(rewriter, loc, reg.getDone());
646 op.getResult().replaceAllUsesWith(reg.getOut());
648 if (isa<calyx::AddFOpIEEE754>(opPipe)) {
649 auto opFOp = cast<calyx::AddFOpIEEE754>(opPipe);
651 if (isa<arith::AddFOp>(op)) {
652 subOp = createConstant(loc, rewriter,
getComponent(), 1,
655 subOp = createConstant(loc, rewriter,
getComponent(), 1,
658 calyx::AssignOp::create(rewriter, loc, opFOp.getSubOp(), subOp);
659 }
else if (
auto opFOp =
660 dyn_cast<calyx::DivSqrtOpIEEE754>(opPipe.getOperation())) {
661 bool isSqrt = !isa<arith::DivFOp>(op);
663 createConstant(loc, rewriter,
getComponent(), 1, isSqrt);
664 calyx::AssignOp::create(rewriter, loc, opFOp.getSqrtOp(), sqrtOp);
668 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
669 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
671 getState<ComponentLoweringState>().registerEvaluatingGroup(
672 opPipe.getRight(), group);
674 getState<ComponentLoweringState>().setSeqResReg(out.getDefiningOp(), reg);
679 template <
typename TCalyxLibOp,
typename TSrcOp>
681 unsigned inputWidth,
unsigned outputWidth,
682 StringRef signedPort)
const {
683 Location loc = op.getLoc();
684 IntegerType one = rewriter.getI1Type(),
685 inWidth = rewriter.getIntegerType(inputWidth),
686 outWidth = rewriter.getIntegerType(outputWidth);
688 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
689 rewriter, loc, {one, one, one, inWidth, one, outWidth, one});
691 StringRef opName = op.getOperationName().split(
".").second;
693 auto reg = createRegister(
694 loc, rewriter,
getComponent(), outWidth.getIntOrFloatBitWidth(),
695 getState<ComponentLoweringState>().getUniqueName(opName));
697 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
698 OpBuilder builder(group->getRegion(0));
699 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
702 rewriter.setInsertionPointToEnd(group.getBodyBlock());
703 calyx::AssignOp::create(rewriter, loc, calyxOp.getIn(), op.getIn());
704 if (isa<calyx::FpToIntOpIEEE754>(calyxOp)) {
705 calyx::AssignOp::create(
706 rewriter, loc, cast<calyx::FpToIntOpIEEE754>(calyxOp).getSignedOut(),
708 }
else if (isa<calyx::IntToFpOpIEEE754>(calyxOp)) {
709 calyx::AssignOp::create(
710 rewriter, loc, cast<calyx::IntToFpOpIEEE754>(calyxOp).getSignedIn(),
713 op.getResult().replaceAllUsesWith(reg.getOut());
715 calyx::AssignOp::create(rewriter, loc, reg.getIn(), calyxOp.getOut());
716 calyx::AssignOp::create(rewriter, loc, reg.getWriteEn(), c1);
718 calyx::AssignOp::create(
719 rewriter, loc, calyxOp.getGo(), c1,
721 calyx::GroupDoneOp::create(rewriter, loc, reg.getDone());
729 calyx::GroupInterface group,
731 Operation::operand_range addressValues)
const {
732 IRRewriter::InsertionGuard guard(rewriter);
733 rewriter.setInsertionPointToEnd(group.getBody());
734 auto addrPorts = memoryInterface.
addrPorts();
735 if (addressValues.empty()) {
737 addrPorts.size() == 1 &&
738 "We expected a 1 dimensional memory of size 1 because there were no "
739 "address assignment values");
741 calyx::AssignOp::create(
742 rewriter, loc, addrPorts[0],
745 assert(addrPorts.size() == addressValues.size() &&
746 "Mismatch between number of address ports of the provided memory "
747 "and address assignment values");
748 for (
auto address : enumerate(addressValues))
749 calyx::AssignOp::create(rewriter, loc, addrPorts[address.index()],
755 Value signal,
bool invert,
756 StringRef nameSuffix,
757 calyx::CompareFOpIEEE754 calyxCmpFOp,
758 calyx::GroupOp group)
const {
759 Location loc = calyxCmpFOp.getLoc();
760 IntegerType one = rewriter.getI1Type();
762 OpBuilder builder(group->getRegion(0));
763 auto reg = createRegister(
764 loc, rewriter, component, 1,
765 getState<ComponentLoweringState>().getUniqueName(nameSuffix));
766 calyx::AssignOp::create(rewriter, loc, reg.getWriteEn(),
767 calyxCmpFOp.getDone());
769 auto notLibOp = getState<ComponentLoweringState>()
770 .getNewLibraryOpInstance<calyx::NotLibOp>(
771 rewriter, loc, {one, one});
772 calyx::AssignOp::create(rewriter, loc, notLibOp.getIn(), signal);
773 calyx::AssignOp::create(rewriter, loc, reg.getIn(), notLibOp.getOut());
774 getState<ComponentLoweringState>().registerEvaluatingGroup(
775 notLibOp.getOut(), group);
777 calyx::AssignOp::create(rewriter, loc, reg.getIn(), signal);
783 memref::LoadOp loadOp)
const {
784 Value memref = loadOp.getMemref();
785 auto memoryInterface =
786 getState<ComponentLoweringState>().getMemoryInterface(memref);
787 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
789 loadOp.getIndices());
791 rewriter.setInsertionPointToEnd(group.getBodyBlock());
796 createConstant(loadOp.getLoc(), rewriter,
getComponent(), 1, 1);
797 if (memoryInterface.readEnOpt().has_value()) {
800 calyx::AssignOp::create(rewriter, loadOp.getLoc(), memoryInterface.readEn(),
802 regWriteEn = memoryInterface.done();
809 calyx::GroupDoneOp::create(rewriter, loadOp.getLoc(),
810 memoryInterface.done());
820 res = loadOp.getResult();
822 }
else if (memoryInterface.contentEnOpt().has_value()) {
827 calyx::AssignOp::create(rewriter, loadOp.getLoc(),
828 memoryInterface.contentEn(), oneI1);
829 calyx::AssignOp::create(rewriter, loadOp.getLoc(),
830 memoryInterface.writeEn(), zeroI1);
831 regWriteEn = memoryInterface.done();
838 calyx::GroupDoneOp::create(rewriter, loadOp.getLoc(),
839 memoryInterface.done());
849 res = loadOp.getResult();
861 auto reg = createRegister(
863 loadOp.getMemRefType().getElementTypeBitWidth(),
864 getState<ComponentLoweringState>().getUniqueName(
"load"));
865 rewriter.setInsertionPointToEnd(group.getBodyBlock());
866 calyx::AssignOp::create(rewriter, loadOp.getLoc(), reg.getIn(),
867 memoryInterface.readData());
868 calyx::AssignOp::create(rewriter, loadOp.getLoc(), reg.getWriteEn(),
870 calyx::GroupDoneOp::create(rewriter, loadOp.getLoc(), reg.getDone());
871 loadOp.getResult().replaceAllUsesWith(reg.getOut());
875 getState<ComponentLoweringState>().registerEvaluatingGroup(res, group);
876 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
882 memref::StoreOp storeOp)
const {
883 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
884 storeOp.getMemref());
885 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
889 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
892 storeOp.getIndices());
893 rewriter.setInsertionPointToEnd(group.getBodyBlock());
894 calyx::AssignOp::create(rewriter, storeOp.getLoc(),
895 memoryInterface.writeData(),
896 storeOp.getValueToStore());
897 calyx::AssignOp::create(
898 rewriter, storeOp.getLoc(), memoryInterface.writeEn(),
899 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
900 if (memoryInterface.contentEnOpt().has_value()) {
902 calyx::AssignOp::create(
903 rewriter, storeOp.getLoc(), memoryInterface.contentEn(),
904 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
906 calyx::GroupDoneOp::create(rewriter, storeOp.getLoc(),
907 memoryInterface.done());
914 Location loc = mul.getLoc();
915 Type width = mul.getResult().getType(), one = rewriter.getI1Type();
917 getState<ComponentLoweringState>()
918 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
919 rewriter, loc, {one, one, one, width, width, width, one});
920 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
921 rewriter, mul, mulPipe,
927 Location loc = div.getLoc();
928 Type width = div.getResult().getType(), one = rewriter.getI1Type();
930 getState<ComponentLoweringState>()
931 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
932 rewriter, loc, {one, one, one, width, width, width, one});
933 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
934 rewriter, div, divPipe,
940 Location loc = div.getLoc();
941 Type width = div.getResult().getType(), one = rewriter.getI1Type();
943 getState<ComponentLoweringState>()
944 .getNewLibraryOpInstance<calyx::DivSPipeLibOp>(
945 rewriter, loc, {one, one, one, width, width, width, one});
946 return buildLibraryBinaryPipeOp<calyx::DivSPipeLibOp>(
947 rewriter, div, divPipe,
953 Location loc = rem.getLoc();
954 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
956 getState<ComponentLoweringState>()
957 .getNewLibraryOpInstance<calyx::RemUPipeLibOp>(
958 rewriter, loc, {one, one, one, width, width, width, one});
959 return buildLibraryBinaryPipeOp<calyx::RemUPipeLibOp>(
960 rewriter, rem, remPipe,
966 Location loc = rem.getLoc();
967 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
969 getState<ComponentLoweringState>()
970 .getNewLibraryOpInstance<calyx::RemSPipeLibOp>(
971 rewriter, loc, {one, one, one, width, width, width, one});
972 return buildLibraryBinaryPipeOp<calyx::RemSPipeLibOp>(
973 rewriter, rem, remPipe,
979 Location loc = addf.getLoc();
980 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
981 five = rewriter.getIntegerType(5),
982 width = rewriter.getIntegerType(
983 addf.getType().getIntOrFloatBitWidth());
985 getState<ComponentLoweringState>()
986 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
988 {one, one, one, one, one, width, width, three, width, five, one});
989 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, addf, addFOp,
995 Location loc = subf.getLoc();
996 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
997 five = rewriter.getIntegerType(5),
998 width = rewriter.getIntegerType(
999 subf.getType().getIntOrFloatBitWidth());
1001 getState<ComponentLoweringState>()
1002 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
1004 {one, one, one, one, one, width, width, three, width, five, one});
1005 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, subf, subFOp,
1010 MulFOp mulf)
const {
1011 Location loc = mulf.getLoc();
1012 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
1013 five = rewriter.getIntegerType(5),
1014 width = rewriter.getIntegerType(
1015 mulf.getType().getIntOrFloatBitWidth());
1017 getState<ComponentLoweringState>()
1018 .getNewLibraryOpInstance<calyx::MulFOpIEEE754>(
1020 {one, one, one, one, width, width, three, width, five, one});
1021 return buildLibraryBinaryPipeOp<calyx::MulFOpIEEE754>(rewriter, mulf, mulFOp,
1026 CmpFOp cmpf)
const {
1027 Location loc = cmpf.getLoc();
1028 IntegerType one = rewriter.getI1Type(), five = rewriter.getIntegerType(5),
1029 width = rewriter.getIntegerType(
1030 cmpf.getLhs().getType().getIntOrFloatBitWidth());
1031 auto calyxCmpFOp = getState<ComponentLoweringState>()
1032 .getNewLibraryOpInstance<calyx::CompareFOpIEEE754>(
1034 {one, one, one, width, width, one, one, one, one,
1041 using CombLogic = PredicateInfo::CombLogic;
1042 using Port = PredicateInfo::InputPorts::Port;
1044 if (info.logic == CombLogic::None) {
1045 if (cmpf.getPredicate() == CmpFPredicate::AlwaysTrue) {
1046 cmpf.getResult().replaceAllUsesWith(c1);
1050 if (cmpf.getPredicate() == CmpFPredicate::AlwaysFalse) {
1051 cmpf.getResult().replaceAllUsesWith(c0);
1057 StringRef opName = cmpf.getOperationName().split(
".").second;
1060 getState<ComponentLoweringState>().getUniqueName(opName));
1063 auto group = createGroupForOp<calyx::GroupOp>(rewriter, cmpf);
1064 OpBuilder builder(group->getRegion(0));
1065 getState<ComponentLoweringState>().addBlockScheduleable(cmpf->getBlock(),
1068 rewriter.setInsertionPointToEnd(group.getBodyBlock());
1069 calyx::AssignOp::create(rewriter, loc, calyxCmpFOp.getLeft(), cmpf.getLhs());
1070 calyx::AssignOp::create(rewriter, loc, calyxCmpFOp.getRight(), cmpf.getRhs());
1072 bool signalingFlag =
false;
1073 switch (cmpf.getPredicate()) {
1074 case CmpFPredicate::UGT:
1075 case CmpFPredicate::UGE:
1076 case CmpFPredicate::ULT:
1077 case CmpFPredicate::ULE:
1078 case CmpFPredicate::OGT:
1079 case CmpFPredicate::OGE:
1080 case CmpFPredicate::OLT:
1081 case CmpFPredicate::OLE:
1082 signalingFlag =
true;
1084 case CmpFPredicate::UEQ:
1085 case CmpFPredicate::UNE:
1086 case CmpFPredicate::OEQ:
1087 case CmpFPredicate::ONE:
1088 case CmpFPredicate::UNO:
1089 case CmpFPredicate::ORD:
1090 case CmpFPredicate::AlwaysTrue:
1091 case CmpFPredicate::AlwaysFalse:
1092 signalingFlag =
false;
1098 calyx::AssignOp::create(rewriter, loc, calyxCmpFOp.getSignaling(),
1099 signalingFlag ? c1 : c0);
1102 SmallVector<calyx::RegisterOp> inputRegs;
1103 for (
const auto &input : info.inputPorts) {
1105 switch (input.port) {
1107 signal = calyxCmpFOp.getEq();
1111 signal = calyxCmpFOp.getGt();
1115 signal = calyxCmpFOp.getLt();
1118 case Port::Unordered: {
1119 signal = calyxCmpFOp.getUnordered();
1123 std::string nameSuffix =
1124 (input.port == PredicateInfo::InputPorts::Port::Unordered)
1128 nameSuffix, calyxCmpFOp, group);
1129 inputRegs.push_back(signalReg);
1133 Value outputValue, doneValue;
1134 switch (info.logic) {
1135 case CombLogic::None: {
1137 outputValue = inputRegs[0].getOut();
1138 doneValue = inputRegs[0].getDone();
1141 case CombLogic::And: {
1142 auto outputLibOp = getState<ComponentLoweringState>()
1143 .getNewLibraryOpInstance<calyx::AndLibOp>(
1144 rewriter, loc, {one, one, one});
1145 calyx::AssignOp::create(rewriter, loc, outputLibOp.getLeft(),
1146 inputRegs[0].getOut());
1147 calyx::AssignOp::create(rewriter, loc, outputLibOp.getRight(),
1148 inputRegs[1].getOut());
1150 outputValue = outputLibOp.getOut();
1153 case CombLogic::Or: {
1154 auto outputLibOp = getState<ComponentLoweringState>()
1155 .getNewLibraryOpInstance<calyx::OrLibOp>(
1156 rewriter, loc, {one, one, one});
1157 calyx::AssignOp::create(rewriter, loc, outputLibOp.getLeft(),
1158 inputRegs[0].getOut());
1159 calyx::AssignOp::create(rewriter, loc, outputLibOp.getRight(),
1160 inputRegs[1].getOut());
1162 outputValue = outputLibOp.getOut();
1167 if (info.logic != CombLogic::None) {
1168 auto doneLibOp = getState<ComponentLoweringState>()
1169 .getNewLibraryOpInstance<calyx::AndLibOp>(
1170 rewriter, loc, {one, one, one});
1171 calyx::AssignOp::create(rewriter, loc, doneLibOp.getLeft(),
1172 inputRegs[0].getDone());
1173 calyx::AssignOp::create(rewriter, loc, doneLibOp.getRight(),
1174 inputRegs[1].getDone());
1175 doneValue = doneLibOp.getOut();
1179 calyx::AssignOp::create(rewriter, loc, reg.getIn(), outputValue);
1180 calyx::AssignOp::create(rewriter, loc, reg.getWriteEn(), doneValue);
1183 calyx::AssignOp::create(
1184 rewriter, loc, calyxCmpFOp.getGo(), c1,
1186 calyx::GroupDoneOp::create(rewriter, loc, reg.getDone());
1188 cmpf.getResult().replaceAllUsesWith(reg.getOut());
1191 getState<ComponentLoweringState>().registerEvaluatingGroup(outputValue,
1193 getState<ComponentLoweringState>().registerEvaluatingGroup(doneValue, group);
1194 getState<ComponentLoweringState>().registerEvaluatingGroup(
1195 calyxCmpFOp.getLeft(), group);
1196 getState<ComponentLoweringState>().registerEvaluatingGroup(
1197 calyxCmpFOp.getRight(), group);
1203 FPToSIOp fptosi)
const {
1204 return buildFpIntTypeCastOp<calyx::FpToIntOpIEEE754>(
1205 rewriter, fptosi, fptosi.getIn().getType().getIntOrFloatBitWidth(),
1206 fptosi.getOut().getType().getIntOrFloatBitWidth(),
"signedOut");
1210 SIToFPOp sitofp)
const {
1211 return buildFpIntTypeCastOp<calyx::IntToFpOpIEEE754>(
1212 rewriter, sitofp, sitofp.getIn().getType().getIntOrFloatBitWidth(),
1213 sitofp.getOut().getType().getIntOrFloatBitWidth(),
"signedIn");
1217 DivFOp divf)
const {
1218 Location loc = divf.getLoc();
1219 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
1220 five = rewriter.getIntegerType(5),
1221 width = rewriter.getIntegerType(
1222 divf.getType().getIntOrFloatBitWidth());
1223 auto divFOp = getState<ComponentLoweringState>()
1224 .getNewLibraryOpInstance<calyx::DivSqrtOpIEEE754>(
1228 width, three, width,
1230 return buildLibraryBinaryPipeOp<calyx::DivSqrtOpIEEE754>(
1231 rewriter, divf, divFOp, divFOp.getOut());
1235 math::SqrtOp sqrt)
const {
1236 Location loc = sqrt.getLoc();
1237 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
1238 five = rewriter.getIntegerType(5),
1239 width = rewriter.getIntegerType(
1240 sqrt.getType().getIntOrFloatBitWidth());
1241 auto sqrtOp = getState<ComponentLoweringState>()
1242 .getNewLibraryOpInstance<calyx::DivSqrtOpIEEE754>(
1246 width, three, width,
1248 return buildLibraryBinaryPipeOp<calyx::DivSqrtOpIEEE754>(
1249 rewriter, sqrt, sqrtOp, sqrtOp.getOut());
1253 math::AbsFOp absFOp)
const {
1254 Location loc = absFOp.getLoc();
1255 auto input = absFOp.getOperand();
1257 unsigned bitwidth = input.getType().getIntOrFloatBitWidth();
1258 Type intTy = rewriter.getIntegerType(bitwidth);
1260 uint64_t signBit = 1ULL << (bitwidth - 1);
1261 uint64_t absMask = ~signBit & ((1ULL << bitwidth) - 1);
1263 Value maskOp = arith::ConstantIntOp::create(rewriter, loc, intTy, absMask);
1265 auto combGroup = createGroupForOp<calyx::CombGroupOp>(rewriter, absFOp);
1266 rewriter.setInsertionPointToStart(combGroup.getBodyBlock());
1268 auto andLibOp = getState<ComponentLoweringState>()
1269 .getNewLibraryOpInstance<calyx::AndLibOp>(
1270 rewriter, loc, {intTy, intTy, intTy});
1271 calyx::AssignOp::create(rewriter, loc, andLibOp.getLeft(), maskOp);
1272 calyx::AssignOp::create(rewriter, loc, andLibOp.getRight(), input);
1274 getState<ComponentLoweringState>().registerEvaluatingGroup(andLibOp.getOut(),
1276 rewriter.replaceAllUsesWith(absFOp, andLibOp.getOut());
1281template <
typename TAllocOp>
1283 PatternRewriter &rewriter, TAllocOp allocOp) {
1284 rewriter.setInsertionPointToStart(
1286 MemRefType memtype = allocOp.getType();
1287 SmallVector<int64_t> addrSizes;
1288 SmallVector<int64_t> sizes;
1289 for (int64_t dim : memtype.getShape()) {
1290 sizes.push_back(dim);
1295 if (sizes.empty() && addrSizes.empty()) {
1297 addrSizes.push_back(1);
1299 auto memoryOp = calyx::SeqMemoryOp::create(
1300 rewriter, allocOp.getLoc(), componentState.
getUniqueName(
"mem"),
1301 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1305 memoryOp->setAttr(
"external",
1306 IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));
1310 unsigned elmTyBitWidth = memtype.getElementTypeBitWidth();
1311 assert(elmTyBitWidth <= 64 &&
"element bitwidth should not exceed 64");
1312 bool isFloat = !memtype.getElementType().isInteger();
1314 auto shape = allocOp.getType().getShape();
1316 std::reduce(shape.begin(), shape.end(), 1, std::multiplies<int>());
1323 if (!(shape.size() <= 1 || totalSize <= 1)) {
1324 allocOp.emitError(
"input memory dimension must be empty or one.");
1328 std::vector<uint64_t> flattenedVals(totalSize, 0);
1329 if (isa<memref::GetGlobalOp>(allocOp)) {
1330 auto getGlobalOp = cast<memref::GetGlobalOp>(allocOp);
1331 auto *symbolTableOp =
1332 getGlobalOp->template getParentWithTrait<mlir::OpTrait::SymbolTable>();
1333 auto globalOp = dyn_cast_or_null<memref::GlobalOp>(
1334 SymbolTable::lookupSymbolIn(symbolTableOp, getGlobalOp.getNameAttr()));
1336 auto cstAttr = llvm::dyn_cast_or_null<DenseElementsAttr>(
1337 globalOp.getConstantInitValue());
1339 for (
auto attr : cstAttr.template getValues<Attribute>()) {
1340 assert((isa<mlir::FloatAttr, mlir::IntegerAttr>(attr)) &&
1341 "memory attributes must be float or int");
1342 if (
auto fltAttr = dyn_cast<mlir::FloatAttr>(attr)) {
1343 flattenedVals[sizeCount++] =
1344 bit_cast<uint64_t>(fltAttr.getValueAsDouble());
1346 auto intAttr = dyn_cast<mlir::IntegerAttr>(attr);
1347 APInt value = intAttr.getValue();
1348 flattenedVals[sizeCount++] = *value.getRawData();
1352 rewriter.eraseOp(globalOp);
1355 llvm::json::Array result;
1356 result.reserve(std::max(
static_cast<int>(shape.size()), 1));
1358 Type elemType = memtype.getElementType();
1360 !elemType.isSignlessInteger() && !elemType.isUnsignedInteger();
1361 for (uint64_t bitValue : flattenedVals) {
1362 llvm::json::Value value = 0;
1366 value = bit_cast<double>(bitValue);
1368 APInt apInt(elmTyBitWidth, bitValue, isSigned,
1373 value =
static_cast<int64_t
>(apInt.getSExtValue());
1375 value = apInt.getZExtValue();
1377 result.push_back(std::move(value));
1380 componentState.
setDataField(memoryOp.getName(), result);
1381 std::string numType =
1382 memtype.getElementType().isInteger() ?
"bitnum" :
"ieee754_float";
1383 componentState.
setFormat(memoryOp.getName(), numType, isSigned,
1390 memref::AllocOp allocOp)
const {
1391 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1395 memref::AllocaOp allocOp)
const {
1396 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1400 memref::GetGlobalOp getGlobalOp)
const {
1401 return buildAllocOp(getState<ComponentLoweringState>(), rewriter,
1406 scf::YieldOp yieldOp)
const {
1407 if (yieldOp.getOperands().empty()) {
1408 if (
auto forOp = dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1412 auto inductionReg = getState<ComponentLoweringState>().getForLoopIterReg(
1415 Type regWidth = inductionReg.getOut().getType();
1417 SmallVector<Type> types(3, regWidth);
1418 auto addOp = getState<ComponentLoweringState>()
1419 .getNewLibraryOpInstance<calyx::AddLibOp>(
1420 rewriter, forOp.getLoc(), types);
1422 auto directions = addOp.portDirections();
1424 SmallVector<Value, 2> opInputPorts;
1426 for (
auto dir : enumerate(directions)) {
1427 switch (dir.value()) {
1429 opInputPorts.push_back(addOp.getResult(dir.index()));
1433 opOutputPort = addOp.getResult(dir.index());
1441 getState<ComponentLoweringState>().getComponentOp();
1442 SmallVector<StringRef, 4> groupIdentifier = {
1443 "incr", getState<ComponentLoweringState>().getUniqueName(forOp),
1444 "induction",
"var"};
1445 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1447 llvm::join(groupIdentifier,
"_"));
1448 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
1451 Value leftOp = opInputPorts.front();
1452 calyx::AssignOp::create(rewriter, forOp.getLoc(), leftOp,
1453 inductionReg.getOut());
1455 Value rightOp = opInputPorts.back();
1456 calyx::AssignOp::create(
1457 rewriter, forOp.getLoc(), rightOp,
1458 createConstant(forOp->getLoc(), rewriter,
componentOp,
1459 regWidth.getIntOrFloatBitWidth(),
1460 forOp.getConstantStep().value().getSExtValue()));
1462 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp,
1463 inductionReg, opOutputPort);
1465 getState<ComponentLoweringState>().setForLoopLatchGroup(forOpInterface,
1467 getState<ComponentLoweringState>().registerEvaluatingGroup(opOutputPort,
1471 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp()))
1474 if (
auto executeRegionOp =
1475 dyn_cast<scf::ExecuteRegionOp>(yieldOp->getParentOp()))
1478 return yieldOp.getOperation()->emitError()
1479 <<
"Unsupported empty yieldOp outside ForOp or IfOp.";
1482 if (dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1483 return yieldOp.getOperation()->emitError()
1484 <<
"Currently do not support non-empty yield operations inside for "
1485 "loops. Run --scf-for-to-while before running --scf-to-calyx.";
1488 if (
auto whileOp = dyn_cast<scf::WhileOp>(yieldOp->getParentOp())) {
1492 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1493 rewriter, whileOpInterface,
1494 getState<ComponentLoweringState>().getComponentOp(),
1495 getState<ComponentLoweringState>().getUniqueName(whileOp) +
1497 yieldOp->getOpOperands());
1498 getState<ComponentLoweringState>().setWhileLoopLatchGroup(whileOpInterface,
1503 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp())) {
1504 auto resultRegs = getState<ComponentLoweringState>().getResultRegs(ifOp);
1506 if (yieldOp->getParentRegion() == &ifOp.getThenRegion()) {
1507 auto thenGroup = getState<ComponentLoweringState>().getThenGroup(ifOp);
1508 for (
auto op : enumerate(yieldOp.getOperands())) {
1510 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1511 buildAssignmentsForRegisterWrite(
1512 rewriter, thenGroup,
1513 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1515 getState<ComponentLoweringState>().registerEvaluatingGroup(
1516 ifOp.getResult(op.index()), thenGroup);
1520 if (!ifOp.getElseRegion().empty() &&
1521 (yieldOp->getParentRegion() == &ifOp.getElseRegion())) {
1522 auto elseGroup = getState<ComponentLoweringState>().getElseGroup(ifOp);
1523 for (
auto op : enumerate(yieldOp.getOperands())) {
1525 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1526 buildAssignmentsForRegisterWrite(
1527 rewriter, elseGroup,
1528 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1530 getState<ComponentLoweringState>().registerEvaluatingGroup(
1531 ifOp.getResult(op.index()), elseGroup);
1539 BranchOpInterface brOp)
const {
1544 Block *srcBlock = brOp->getBlock();
1545 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
1546 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
1547 if (succOperands.empty())
1552 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1553 brOp.getLoc(), groupName);
1555 auto dstBlockArgRegs =
1556 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
1558 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
1559 auto reg = dstBlockArgRegs[arg.index()];
1562 getState<ComponentLoweringState>().getComponentOp(), reg,
1567 getState<ComponentLoweringState>().addBlockArgGroup(
1568 srcBlock, succBlock.value(), groupOp);
1576 ReturnOp retOp)
const {
1577 if (retOp.getNumOperands() == 0)
1580 std::string groupName =
1581 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
1582 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1583 retOp.getLoc(), groupName);
1584 for (
auto op : enumerate(retOp.getOperands())) {
1585 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
1587 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
1591 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
1597 arith::ConstantOp constOp)
const {
1598 if (isa<IntegerType>(constOp.getType())) {
1607 std::string name = getState<ComponentLoweringState>().getUniqueName(
"cst");
1608 auto floatAttr = cast<FloatAttr>(constOp.getValueAttr());
1610 rewriter.getIntegerType(floatAttr.getType().getIntOrFloatBitWidth());
1611 auto calyxConstOp = calyx::ConstantOp::create(rewriter, constOp.getLoc(),
1612 name, floatAttr, intType);
1615 rewriter.replaceAllUsesWith(constOp, calyxConstOp.getOut());
1623 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
1627 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
1631 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
1635 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
1639 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
1643 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
1647 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
1651 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
1654 SelectOp op)
const {
1655 return buildLibraryOp<calyx::CombGroupOp, calyx::MuxLibOp>(rewriter, op);
1660 switch (op.getPredicate()) {
1661 case CmpIPredicate::eq:
1662 return buildCmpIOpHelper<calyx::EqLibOp>(rewriter, op);
1663 case CmpIPredicate::ne:
1664 return buildCmpIOpHelper<calyx::NeqLibOp>(rewriter, op);
1665 case CmpIPredicate::uge:
1666 return buildCmpIOpHelper<calyx::GeLibOp>(rewriter, op);
1667 case CmpIPredicate::ult:
1668 return buildCmpIOpHelper<calyx::LtLibOp>(rewriter, op);
1669 case CmpIPredicate::ugt:
1670 return buildCmpIOpHelper<calyx::GtLibOp>(rewriter, op);
1671 case CmpIPredicate::ule:
1672 return buildCmpIOpHelper<calyx::LeLibOp>(rewriter, op);
1673 case CmpIPredicate::sge:
1674 return buildCmpIOpHelper<calyx::SgeLibOp>(rewriter, op);
1675 case CmpIPredicate::slt:
1676 return buildCmpIOpHelper<calyx::SltLibOp>(rewriter, op);
1677 case CmpIPredicate::sgt:
1678 return buildCmpIOpHelper<calyx::SgtLibOp>(rewriter, op);
1679 case CmpIPredicate::sle:
1680 return buildCmpIOpHelper<calyx::SleLibOp>(rewriter, op);
1682 llvm_unreachable(
"unsupported comparison predicate");
1686 TruncIOp op)
const {
1687 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1688 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1692 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1693 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1698 return buildLibraryOp<calyx::CombGroupOp, calyx::ExtSILibOp>(
1699 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1703 IndexCastOp op)
const {
1706 unsigned targetBits = targetType.getIntOrFloatBitWidth();
1707 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
1708 LogicalResult res = success();
1710 if (targetBits == sourceBits) {
1713 op.getResult().replaceAllUsesWith(op.getOperand());
1716 if (sourceBits > targetBits)
1717 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1718 rewriter, op, {sourceType}, {targetType});
1720 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1721 rewriter, op, {sourceType}, {targetType});
1723 rewriter.eraseOp(op);
1730 BitcastOp op)
const {
1731 rewriter.replaceAllUsesWith(op.getOut(), op.getIn());
1736 scf::WhileOp whileOp)
const {
1740 getState<ComponentLoweringState>().addBlockScheduleable(
1746 scf::ForOp forOp)
const {
1752 std::optional<uint64_t> bound = scfForOp.
getBound();
1753 if (!bound.has_value()) {
1755 <<
"Loop bound not statically known. Should "
1756 "transform into while loop using `--scf-for-to-while` before "
1757 "running --lower-scf-to-calyx.";
1759 getState<ComponentLoweringState>().addBlockScheduleable(
1768 scf::IfOp ifOp)
const {
1769 getState<ComponentLoweringState>().addBlockScheduleable(
1775 scf::ReduceOp reduceOp)
const {
1783 scf::ParallelOp parOp)
const {
1786 "AffineParallelUnroll must be run in order to lower scf.parallel");
1789 getState<ComponentLoweringState>().addBlockScheduleable(
1796 scf::ExecuteRegionOp executeRegionOp)
const {
1804 CallOp callOp)
const {
1806 calyx::InstanceOp instanceOp =
1807 getState<ComponentLoweringState>().getInstance(instanceName);
1808 SmallVector<Value, 4> outputPorts;
1809 auto portInfos = instanceOp.getReferencedComponent().getPortInfo();
1810 for (
auto [idx, portInfo] : enumerate(portInfos)) {
1812 outputPorts.push_back(instanceOp.getResult(idx));
1816 for (
auto [idx, result] : llvm::enumerate(callOp.getResults()))
1817 rewriter.replaceAllUsesWith(result, outputPorts[idx]);
1821 getState<ComponentLoweringState>().addBlockScheduleable(
1835 using OpRewritePattern::OpRewritePattern;
1838 PatternRewriter &rewriter)
const override {
1839 if (
auto parOp = dyn_cast_or_null<scf::ParallelOp>(execOp->getParentOp())) {
1840 if (
auto boolAttr = dyn_cast_or_null<mlir::BoolAttr>(
1848 TypeRange yieldTypes = execOp.getResultTypes();
1852 rewriter.setInsertionPointAfter(execOp);
1853 auto *sinkBlock = rewriter.splitBlock(
1855 execOp.getOperation()->getIterator()->getNextNode()->getIterator());
1856 sinkBlock->addArguments(
1858 SmallVector<Location, 4>(yieldTypes.size(), rewriter.getUnknownLoc()));
1859 for (
auto res : enumerate(execOp.getResults()))
1860 res.value().replaceAllUsesWith(sinkBlock->getArgument(res.index()));
1864 make_early_inc_range(execOp.getRegion().getOps<scf::YieldOp>())) {
1865 rewriter.setInsertionPointAfter(yieldOp);
1866 rewriter.replaceOpWithNewOp<BranchOp>(yieldOp, sinkBlock,
1867 yieldOp.getOperands());
1871 auto *preBlock = execOp->getBlock();
1872 auto *execOpEntryBlock = &execOp.getRegion().front();
1873 auto *postBlock = execOp->getBlock()->splitBlock(execOp);
1874 rewriter.inlineRegionBefore(execOp.getRegion(), postBlock);
1875 rewriter.mergeBlocks(postBlock, preBlock);
1876 rewriter.eraseOp(execOp);
1879 rewriter.mergeBlocks(execOpEntryBlock, preBlock);
1887 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1891 PatternRewriter &rewriter)
const override {
1894 DenseMap<Value, unsigned> funcOpArgRewrites;
1898 DenseMap<unsigned, unsigned> funcOpResultMapping;
1906 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
1910 SmallVector<calyx::PortInfo> inPorts, outPorts;
1911 FunctionType funcType = funcOp.getFunctionType();
1912 for (
auto arg : enumerate(funcOp.getArguments())) {
1913 if (!isa<MemRefType>(arg.value().getType())) {
1916 if (
auto portNameAttr = funcOp.getArgAttrOfType<StringAttr>(
1918 inName = portNameAttr.str();
1920 inName =
"in" + std::to_string(arg.index());
1921 funcOpArgRewrites[arg.value()] = inPorts.size();
1923 rewriter.getStringAttr(inName),
1926 DictionaryAttr::get(rewriter.getContext(), {})});
1929 for (
auto res : enumerate(funcType.getResults())) {
1930 std::string resName;
1931 if (
auto portNameAttr = funcOp.getResultAttrOfType<StringAttr>(
1933 resName = portNameAttr.str();
1935 resName =
"out" + std::to_string(res.index());
1936 funcOpResultMapping[res.index()] = outPorts.size();
1939 rewriter.getStringAttr(resName),
1941 DictionaryAttr::get(rewriter.getContext(), {})});
1946 auto ports = inPorts;
1947 llvm::append_range(ports, outPorts);
1951 auto compOp = calyx::ComponentOp::create(
1952 rewriter, funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()),
1955 std::string funcName =
"func_" + funcOp.getSymName().str();
1956 rewriter.modifyOpInPlace(funcOp, [&]() { funcOp.setSymName(funcName); });
1960 if (compOp.getName() ==
loweringState().getTopLevelFunction())
1961 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
1968 unsigned extMemCounter = 0;
1969 for (
auto arg : enumerate(funcOp.getArguments())) {
1970 if (isa<MemRefType>(arg.value().getType())) {
1971 std::string memName =
1972 llvm::join_items(
"_",
"arg_mem", std::to_string(extMemCounter++));
1974 rewriter.setInsertionPointToStart(compOp.getBodyBlock());
1975 MemRefType memtype = cast<MemRefType>(arg.value().getType());
1976 SmallVector<int64_t> addrSizes;
1977 SmallVector<int64_t> sizes;
1978 for (int64_t dim : memtype.getShape()) {
1979 sizes.push_back(dim);
1982 if (sizes.empty() && addrSizes.empty()) {
1984 addrSizes.push_back(1);
1986 auto memOp = calyx::SeqMemoryOp::create(
1987 rewriter, funcOp.getLoc(), memName,
1988 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1991 compState->registerMemoryInterface(arg.value(),
1997 for (
auto &mapping : funcOpArgRewrites)
1998 mapping.getFirst().replaceAllUsesWith(
1999 compOp.getArgument(mapping.getSecond()));
2010 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2014 PatternRewriter &rewriter)
const override {
2015 LogicalResult res = success();
2016 funcOp.walk([&](Operation *op) {
2018 if (!isa<scf::WhileOp>(op))
2019 return WalkResult::advance();
2021 auto scfWhileOp = cast<scf::WhileOp>(op);
2024 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
2034 enumerate(scfWhileOp.getBefore().front().getArguments())) {
2035 auto condOp = scfWhileOp.getConditionOp().getArgs()[barg.index()];
2036 if (barg.value() != condOp) {
2040 <<
"do-while loops not supported; expected iter-args to "
2041 "remain untransformed in the 'before' region of the "
2043 return WalkResult::interrupt();
2052 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
2053 std::string name = getState<ComponentLoweringState>()
2056 "_arg" + std::to_string(arg.index());
2058 createRegister(arg.value().getLoc(), rewriter,
getComponent(),
2059 arg.value().getType().getIntOrFloatBitWidth(), name);
2060 getState<ComponentLoweringState>().addWhileLoopIterReg(whileOp, reg,
2062 arg.value().replaceAllUsesWith(reg.getOut());
2066 ->getArgument(arg.index())
2067 .replaceAllUsesWith(reg.getOut());
2071 SmallVector<calyx::GroupOp> initGroups;
2072 auto numOperands = whileOp.
getOperation()->getNumOperands();
2073 for (
size_t i = 0; i < numOperands; ++i) {
2075 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
2077 getState<ComponentLoweringState>().getComponentOp(),
2078 getState<ComponentLoweringState>().getUniqueName(
2080 "_init_" + std::to_string(i),
2082 initGroups.push_back(initGroupOp);
2085 getState<ComponentLoweringState>().setWhileLoopInitGroups(whileOp,
2088 return WalkResult::advance();
2098 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2102 PatternRewriter &rewriter)
const override {
2103 LogicalResult res = success();
2104 funcOp.walk([&](Operation *op) {
2106 if (!isa<scf::ForOp>(op))
2107 return WalkResult::advance();
2109 auto scfForOp = cast<scf::ForOp>(op);
2112 getState<ComponentLoweringState>().setUniqueName(forOp.
getOperation(),
2117 auto inductionVar = forOp.
getOperation().getInductionVar();
2118 SmallVector<std::string, 3> inductionVarIdentifiers = {
2119 getState<ComponentLoweringState>()
2122 "induction",
"var"};
2123 std::string name = llvm::join(inductionVarIdentifiers,
"_");
2125 createRegister(inductionVar.getLoc(), rewriter,
getComponent(),
2126 inductionVar.getType().getIntOrFloatBitWidth(), name);
2127 getState<ComponentLoweringState>().addForLoopIterReg(forOp, reg, 0);
2128 inductionVar.replaceAllUsesWith(reg.getOut());
2132 getState<ComponentLoweringState>().getComponentOp();
2133 SmallVector<calyx::GroupOp> initGroups;
2134 SmallVector<std::string, 4> groupIdentifiers = {
2136 getState<ComponentLoweringState>()
2139 "induction",
"var"};
2140 std::string groupName = llvm::join(groupIdentifiers,
"_");
2141 auto groupOp = calyx::createGroup<calyx::GroupOp>(
2143 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp, reg,
2145 initGroups.push_back(groupOp);
2146 getState<ComponentLoweringState>().setForLoopInitGroups(forOp,
2149 return WalkResult::advance();
2156 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2160 PatternRewriter &rewriter)
const override {
2161 LogicalResult res = success();
2162 funcOp.walk([&](Operation *op) {
2163 if (!isa<scf::IfOp>(op))
2164 return WalkResult::advance();
2166 auto scfIfOp = cast<scf::IfOp>(op);
2171 if (scfIfOp.getResults().empty())
2172 return WalkResult::advance();
2175 getState<ComponentLoweringState>().getComponentOp();
2177 std::string thenGroupName =
2178 getState<ComponentLoweringState>().getUniqueName(
"then_br");
2179 auto thenGroupOp = calyx::createGroup<calyx::GroupOp>(
2180 rewriter,
componentOp, scfIfOp.getLoc(), thenGroupName);
2181 getState<ComponentLoweringState>().setThenGroup(scfIfOp, thenGroupOp);
2183 if (!scfIfOp.getElseRegion().empty()) {
2184 std::string elseGroupName =
2185 getState<ComponentLoweringState>().getUniqueName(
"else_br");
2186 auto elseGroupOp = calyx::createGroup<calyx::GroupOp>(
2187 rewriter,
componentOp, scfIfOp.getLoc(), elseGroupName);
2188 getState<ComponentLoweringState>().setElseGroup(scfIfOp, elseGroupOp);
2191 for (
auto ifOpRes : scfIfOp.getResults()) {
2192 auto reg = createRegister(
2194 ifOpRes.getType().getIntOrFloatBitWidth(),
2195 getState<ComponentLoweringState>().getUniqueName(
"if_res"));
2196 getState<ComponentLoweringState>().setResultRegs(
2197 scfIfOp, reg, ifOpRes.getResultNumber());
2200 return WalkResult::advance();
2212 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2216 PatternRewriter &rewriter)
const override {
2217 auto *entryBlock = &funcOp.getBlocks().front();
2218 rewriter.setInsertionPointToStart(
2220 auto topLevelSeqOp = calyx::SeqOp::create(rewriter, funcOp.getLoc());
2221 DenseSet<Block *> path;
2223 nullptr, entryBlock);
2230 const DenseSet<Block *> &path,
2231 mlir::Block *parentCtrlBlock,
2232 mlir::Block *block)
const {
2233 auto compBlockScheduleables =
2234 getState<ComponentLoweringState>().getBlockScheduleables(block);
2235 auto loc = block->front().getLoc();
2237 if (compBlockScheduleables.size() > 1 &&
2238 !isa<scf::ParallelOp>(block->getParentOp())) {
2239 auto seqOp = calyx::SeqOp::create(rewriter, loc);
2240 parentCtrlBlock = seqOp.getBodyBlock();
2243 for (
auto &group : compBlockScheduleables) {
2244 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2245 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
2246 calyx::EnableOp::create(rewriter, groupPtr->getLoc(),
2247 groupPtr->getSymName());
2248 }
else if (
auto whileSchedPtr = std::get_if<WhileScheduleable>(&group);
2250 auto &whileOp = whileSchedPtr->whileOp;
2254 getState<ComponentLoweringState>().getWhileLoopInitGroups(whileOp),
2256 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
2258 calyx::SeqOp::create(rewriter, whileOp.getOperation()->getLoc());
2259 auto *whileBodyOpBlock = whileBodyOp.getBodyBlock();
2263 if (LogicalResult result =
2265 whileOp.getBodyBlock());
2270 rewriter.setInsertionPointToEnd(whileBodyOpBlock);
2271 calyx::GroupOp whileLatchGroup =
2272 getState<ComponentLoweringState>().getWhileLoopLatchGroup(whileOp);
2273 calyx::EnableOp::create(rewriter, whileLatchGroup.getLoc(),
2274 whileLatchGroup.getName());
2275 }
else if (
auto *parSchedPtr = std::get_if<ParScheduleable>(&group)) {
2276 auto parOp = parSchedPtr->parOp;
2277 auto calyxParOp = calyx::ParOp::create(rewriter, parOp.getLoc());
2279 WalkResult walkResult =
2280 parOp.walk([&](scf::ExecuteRegionOp execRegion) {
2281 rewriter.setInsertionPointToEnd(calyxParOp.getBodyBlock());
2282 auto seqOp = calyx::SeqOp::create(rewriter, execRegion.getLoc());
2283 rewriter.setInsertionPointToEnd(seqOp.getBodyBlock());
2285 for (
auto &execBlock : execRegion.getRegion().getBlocks()) {
2287 rewriter, path, seqOp.getBodyBlock(), &execBlock);
2289 return WalkResult::interrupt();
2292 return WalkResult::advance();
2295 if (walkResult.wasInterrupted())
2297 }
else if (
auto *forSchedPtr = std::get_if<ForScheduleable>(&group);
2299 auto forOp = forSchedPtr->forOp;
2303 getState<ComponentLoweringState>().getForLoopInitGroups(forOp),
2304 forSchedPtr->bound, rewriter);
2305 rewriter.setInsertionPointToEnd(forCtrlOp.getBodyBlock());
2307 calyx::SeqOp::create(rewriter, forOp.getOperation()->getLoc());
2308 auto *forBodyOpBlock = forBodyOp.getBodyBlock();
2311 if (LogicalResult res =
buildCFGControl(path, rewriter, forBodyOpBlock,
2312 block, forOp.getBodyBlock());
2317 rewriter.setInsertionPointToEnd(forBodyOpBlock);
2318 calyx::GroupOp forLatchGroup =
2319 getState<ComponentLoweringState>().getForLoopLatchGroup(forOp);
2320 calyx::EnableOp::create(rewriter, forLatchGroup.getLoc(),
2321 forLatchGroup.getName());
2322 }
else if (
auto *ifSchedPtr = std::get_if<IfScheduleable>(&group);
2324 auto ifOp = ifSchedPtr->ifOp;
2326 Location loc = ifOp->getLoc();
2328 auto cond = ifOp.getCondition();
2330 FlatSymbolRefAttr symbolAttr =
nullptr;
2331 auto condReg = getState<ComponentLoweringState>().getCondReg(ifOp);
2333 auto condGroup = getState<ComponentLoweringState>()
2334 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2336 symbolAttr = FlatSymbolRefAttr::get(
2337 StringAttr::get(getContext(), condGroup.getSymName()));
2340 bool initElse = !ifOp.getElseRegion().empty();
2341 auto ifCtrlOp = calyx::IfOp::create(rewriter, loc, cond, symbolAttr,
2344 rewriter.setInsertionPointToEnd(ifCtrlOp.getBodyBlock());
2347 calyx::SeqOp::create(rewriter, ifOp.getThenRegion().getLoc());
2348 auto *thenSeqOpBlock = thenSeqOp.getBodyBlock();
2350 auto *thenBlock = &ifOp.getThenRegion().front();
2358 if (!ifOp.getResults().empty()) {
2359 rewriter.setInsertionPointToEnd(thenSeqOpBlock);
2360 calyx::GroupOp thenGroup =
2361 getState<ComponentLoweringState>().getThenGroup(ifOp);
2362 calyx::EnableOp::create(rewriter, thenGroup.getLoc(),
2363 thenGroup.getName());
2366 if (!ifOp.getElseRegion().empty()) {
2367 rewriter.setInsertionPointToEnd(ifCtrlOp.getElseBody());
2370 calyx::SeqOp::create(rewriter, ifOp.getElseRegion().getLoc());
2371 auto *elseSeqOpBlock = elseSeqOp.getBodyBlock();
2373 auto *elseBlock = &ifOp.getElseRegion().front();
2379 if (!ifOp.getResults().empty()) {
2380 rewriter.setInsertionPointToEnd(elseSeqOpBlock);
2381 calyx::GroupOp elseGroup =
2382 getState<ComponentLoweringState>().getElseGroup(ifOp);
2383 calyx::EnableOp::create(rewriter, elseGroup.getLoc(),
2384 elseGroup.getName());
2387 }
else if (
auto *callSchedPtr = std::get_if<CallScheduleable>(&group)) {
2388 auto instanceOp = callSchedPtr->instanceOp;
2389 OpBuilder::InsertionGuard g(rewriter);
2390 auto callBody = calyx::SeqOp::create(rewriter, instanceOp.getLoc());
2391 rewriter.setInsertionPointToStart(callBody.getBodyBlock());
2393 auto callee = callSchedPtr->callOp.getCallee();
2394 auto *calleeOp = SymbolTable::lookupNearestSymbolFrom(
2395 callSchedPtr->callOp.getOperation()->getParentOp(),
2396 StringAttr::get(rewriter.getContext(),
"func_" + callee.str()));
2397 FuncOp calleeFunc = dyn_cast_or_null<FuncOp>(calleeOp);
2399 auto instanceOpComp =
2400 llvm::cast<calyx::ComponentOp>(instanceOp.getReferencedComponent());
2401 auto *instanceOpLoweringState =
2404 SmallVector<Value, 4> instancePorts;
2405 SmallVector<Value, 4> inputPorts;
2406 SmallVector<Attribute, 4> refCells;
2407 for (
auto operandEnum : enumerate(callSchedPtr->callOp.getOperands())) {
2408 auto operand = operandEnum.value();
2409 auto index = operandEnum.index();
2410 if (!isa<MemRefType>(operand.getType())) {
2411 inputPorts.push_back(operand);
2415 auto memOpName = getState<ComponentLoweringState>()
2416 .getMemoryInterface(operand)
2418 auto memOpNameAttr =
2419 SymbolRefAttr::get(rewriter.getContext(), memOpName);
2420 Value argI = calleeFunc.getArgument(index);
2421 if (isa<MemRefType>(argI.getType())) {
2422 NamedAttrList namedAttrList;
2423 namedAttrList.append(
2424 rewriter.getStringAttr(
2425 instanceOpLoweringState->getMemoryInterface(argI)
2429 DictionaryAttr::get(rewriter.getContext(), namedAttrList));
2432 llvm::copy(instanceOp.getResults().take_front(inputPorts.size()),
2433 std::back_inserter(instancePorts));
2435 ArrayAttr refCellsAttr =
2436 ArrayAttr::get(rewriter.getContext(), refCells);
2438 calyx::InvokeOp::create(rewriter, instanceOp.getLoc(),
2439 instanceOp.getSymName(), instancePorts,
2440 inputPorts, refCellsAttr,
2441 ArrayAttr::get(rewriter.getContext(), {}),
2442 ArrayAttr::get(rewriter.getContext(), {}));
2444 llvm_unreachable(
"Unknown scheduleable");
2455 const DenseSet<Block *> &path, Location loc,
2456 Block *from, Block *to,
2457 Block *parentCtrlBlock)
const {
2460 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2461 auto preSeqOp = calyx::SeqOp::create(rewriter, loc);
2462 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
2464 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
2465 calyx::EnableOp::create(rewriter, barg.getLoc(), barg.getSymName());
2471 PatternRewriter &rewriter,
2472 mlir::Block *parentCtrlBlock,
2473 mlir::Block *preBlock,
2474 mlir::Block *block)
const {
2475 if (path.count(block) != 0)
2476 return preBlock->getTerminator()->emitError()
2477 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
2478 "'scf.for' operations.";
2480 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2481 LogicalResult bbSchedResult =
2483 if (bbSchedResult.failed())
2484 return bbSchedResult;
2487 auto successors = block->getSuccessors();
2488 auto nSuccessors = successors.size();
2489 if (nSuccessors > 0) {
2490 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
2492 if (nSuccessors > 1) {
2496 assert(nSuccessors == 2 &&
2497 "only conditional branches supported for now...");
2499 auto cond = brOp->getOperand(0);
2500 auto condGroup = getState<ComponentLoweringState>()
2501 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2502 auto symbolAttr = FlatSymbolRefAttr::get(
2503 StringAttr::get(getContext(), condGroup.getSymName()));
2506 calyx::IfOp::create(rewriter, brOp->getLoc(), cond, symbolAttr,
2508 rewriter.setInsertionPointToStart(ifOp.getThenBody());
2509 auto thenSeqOp = calyx::SeqOp::create(rewriter, brOp.getLoc());
2510 rewriter.setInsertionPointToStart(ifOp.getElseBody());
2511 auto elseSeqOp = calyx::SeqOp::create(rewriter, brOp.getLoc());
2513 bool trueBrSchedSuccess =
2514 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
2515 thenSeqOp.getBodyBlock())
2517 bool falseBrSchedSuccess =
true;
2518 if (trueBrSchedSuccess) {
2519 falseBrSchedSuccess =
2520 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
2521 elseSeqOp.getBodyBlock())
2525 return success(trueBrSchedSuccess && falseBrSchedSuccess);
2528 return schedulePath(rewriter, path, brOp.getLoc(), block,
2529 successors.front(), parentCtrlBlock);
2539 const SmallVector<calyx::GroupOp> &initGroups)
const {
2540 PatternRewriter::InsertionGuard g(rewriter);
2541 auto parOp = calyx::ParOp::create(rewriter, loc);
2542 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
2543 for (calyx::GroupOp group : initGroups)
2544 calyx::EnableOp::create(rewriter, group.getLoc(), group.getName());
2548 SmallVector<calyx::GroupOp> initGroups,
2549 PatternRewriter &rewriter)
const {
2550 Location loc = whileOp.
getLoc();
2557 auto condGroup = getState<ComponentLoweringState>()
2558 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2559 auto symbolAttr = FlatSymbolRefAttr::get(
2560 StringAttr::get(getContext(), condGroup.getSymName()));
2561 return calyx::WhileOp::create(rewriter, loc, cond, symbolAttr);
2565 SmallVector<calyx::GroupOp>
const &initGroups,
2567 PatternRewriter &rewriter)
const {
2568 Location loc = forOp.
getLoc();
2574 return calyx::RepeatOp::create(rewriter, loc, bound);
2581 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2584 PatternRewriter &)
const override {
2585 funcOp.walk([&](scf::IfOp op) {
2586 for (
auto res : getState<ComponentLoweringState>().getResultRegs(op))
2587 op.getOperation()->getResults()[res.first].replaceAllUsesWith(
2588 res.second.getOut());
2591 funcOp.walk([&](scf::WhileOp op) {
2600 getState<ComponentLoweringState>().getWhileLoopIterRegs(whileOp))
2601 whileOp.
getOperation()->getResults()[res.first].replaceAllUsesWith(
2602 res.second.getOut());
2605 funcOp.walk([&](memref::LoadOp loadOp) {
2611 loadOp.getResult().replaceAllUsesWith(
2612 getState<ComponentLoweringState>()
2613 .getMemoryInterface(loadOp.getMemref())
2624 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2627 PatternRewriter &rewriter)
const override {
2628 rewriter.eraseOp(funcOp);
2634 PatternRewriter &rewriter)
const override {
56namespace scftocalyx {
…}
2648class SCFToCalyxPass :
public circt::impl::SCFToCalyxBase<SCFToCalyxPass> {
2650 SCFToCalyxPass(std::string topLevelFunction)
2652 this->topLevelFunctionOpt = topLevelFunction;
2654 void runOnOperation()
override;
2656 LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp,
2657 std::string &topLevelFunction) {
2658 if (!topLevelFunctionOpt.empty()) {
2659 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
2661 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
2662 <<
"' not found in module.";
2665 topLevelFunction = topLevelFunctionOpt;
2669 auto funcOps = moduleOp.getOps<FuncOp>();
2670 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
2671 topLevelFunction = (*funcOps.begin()).getSymName().str();
2673 moduleOp.emitError()
2674 <<
"Module contains multiple functions, but no top level "
2675 "function was set. Please see --top-level-function";
2680 return createOptNewTopLevelFn(moduleOp, topLevelFunction);
2683 struct LoweringPattern {
2684 enum class Strategy { Once, Greedy };
2693 LogicalResult labelEntryPoint(StringRef topLevelFunction) {
2697 using OpRewritePattern::OpRewritePattern;
2698 LogicalResult matchAndRewrite(mlir::ModuleOp,
2699 PatternRewriter &)
const override {
2704 ConversionTarget target(getContext());
2705 target.addLegalDialect<calyx::CalyxDialect>();
2706 target.addLegalDialect<scf::SCFDialect>();
2707 target.addIllegalDialect<hw::HWDialect>();
2708 target.addIllegalDialect<comb::CombDialect>();
2711 target.addIllegalDialect<FuncDialect>();
2712 target.addIllegalDialect<ArithDialect>();
2714 AddIOp, SelectOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
2715 XOrIOp, OrIOp, ExtUIOp, TruncIOp, CondBranchOp, BranchOp, MulIOp,
2716 DivUIOp, DivSIOp, RemUIOp, RemSIOp, ReturnOp, arith::ConstantOp,
2717 IndexCastOp, BitcastOp, FuncOp, ExtSIOp, CallOp, AddFOp, SubFOp, MulFOp,
2718 CmpFOp, FPToSIOp, SIToFPOp, DivFOp, math::SqrtOp>();
2720 RewritePatternSet legalizePatterns(&getContext());
2721 legalizePatterns.add<DummyPattern>(&getContext());
2722 DenseSet<Operation *> legalizedOps;
2723 if (applyPartialConversion(getOperation(), target,
2724 std::move(legalizePatterns))
2735 template <
typename TPattern,
typename... PatternArgs>
2736 void addOncePattern(SmallVectorImpl<LoweringPattern> &
patterns,
2737 PatternArgs &&...args) {
2738 RewritePatternSet ps(&getContext());
2741 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Once});
2744 template <
typename TPattern,
typename... PatternArgs>
2745 void addGreedyPattern(SmallVectorImpl<LoweringPattern> &
patterns,
2746 PatternArgs &&...args) {
2747 RewritePatternSet ps(&getContext());
2748 ps.add<TPattern>(&getContext(), args...);
2750 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Greedy});
2753 LogicalResult runPartialPattern(RewritePatternSet &
pattern,
bool runOnce) {
2755 "Should only apply 1 partial lowering pattern at once");
2761 GreedyRewriteConfig config;
2762 config.setRegionSimplificationLevel(
2763 mlir::GreedySimplifyRegionLevel::Disabled);
2765 config.setMaxIterations(1);
2770 (void)applyPatternsGreedily(getOperation(), std::move(
pattern), config);
2779 FuncOp createNewTopLevelFn(ModuleOp moduleOp, std::string &baseName) {
2780 std::string newName =
"main";
2782 if (
auto *existingMainOp = SymbolTable::lookupSymbolIn(moduleOp, newName)) {
2783 auto existingMainFunc = dyn_cast<FuncOp>(existingMainOp);
2784 if (existingMainFunc ==
nullptr) {
2785 moduleOp.emitError() <<
"Symbol 'main' exists but is not a function";
2788 unsigned counter = 0;
2789 std::string newOldName = baseName;
2790 while (SymbolTable::lookupSymbolIn(moduleOp, newOldName))
2791 newOldName = llvm::join_items(
"_", baseName, std::to_string(++counter));
2792 existingMainFunc.setName(newOldName);
2793 if (baseName ==
"main")
2794 baseName = newOldName;
2798 OpBuilder builder(moduleOp.getContext());
2799 builder.setInsertionPointToStart(moduleOp.getBody());
2801 FunctionType funcType = builder.getFunctionType({}, {});
2804 FuncOp::create(builder, moduleOp.getLoc(), newName, funcType))
2814 void insertCallFromNewTopLevel(OpBuilder &builder, FuncOp caller,
2816 if (caller.getBody().empty()) {
2817 caller.addEntryBlock();
2820 Block *callerEntryBlock = &caller.getBody().front();
2821 builder.setInsertionPointToStart(callerEntryBlock);
2825 SmallVector<Type, 4> nonMemRefCalleeArgTypes;
2826 for (
auto arg : callee.getArguments()) {
2827 if (!isa<MemRefType>(arg.getType())) {
2828 nonMemRefCalleeArgTypes.push_back(arg.getType());
2832 for (Type type : nonMemRefCalleeArgTypes) {
2833 callerEntryBlock->addArgument(type, caller.getLoc());
2836 FunctionType callerFnType = caller.getFunctionType();
2837 SmallVector<Type, 4> updatedCallerArgTypes(
2838 caller.getFunctionType().getInputs());
2839 updatedCallerArgTypes.append(nonMemRefCalleeArgTypes.begin(),
2840 nonMemRefCalleeArgTypes.end());
2841 caller.setType(FunctionType::get(caller.getContext(), updatedCallerArgTypes,
2842 callerFnType.getResults()));
2844 Block *calleeFnBody = &callee.getBody().front();
2845 unsigned originalCalleeArgNum = callee.getArguments().size();
2847 SmallVector<Value, 4> extraMemRefArgs;
2848 SmallVector<Type, 4> extraMemRefArgTypes;
2849 SmallVector<Value, 4> extraMemRefOperands;
2850 SmallVector<Operation *, 4> opsToModify;
2851 for (
auto &op : callee.getBody().getOps()) {
2852 if (isa<memref::AllocaOp, memref::AllocOp, memref::GetGlobalOp>(op))
2853 opsToModify.push_back(&op);
2858 builder.setInsertionPointToEnd(callerEntryBlock);
2859 for (
auto *op : opsToModify) {
2862 TypeSwitch<Operation *>(op)
2863 .Case<memref::AllocaOp>([&](memref::AllocaOp allocaOp) {
2864 newOpRes = memref::AllocaOp::create(builder, callee.getLoc(),
2865 allocaOp.getType());
2867 .Case<memref::AllocOp>([&](memref::AllocOp allocOp) {
2868 newOpRes = memref::AllocOp::create(builder, callee.getLoc(),
2871 .Case<memref::GetGlobalOp>([&](memref::GetGlobalOp getGlobalOp) {
2872 newOpRes = memref::GetGlobalOp::create(builder, caller.getLoc(),
2873 getGlobalOp.getType(),
2874 getGlobalOp.getName());
2876 .Default([&](Operation *defaultOp) {
2877 llvm::report_fatal_error(
"Unsupported operation in TypeSwitch");
2879 extraMemRefOperands.push_back(newOpRes);
2881 calleeFnBody->addArgument(newOpRes.getType(), callee.getLoc());
2882 BlockArgument newBodyArg = calleeFnBody->getArguments().back();
2883 op->getResult(0).replaceAllUsesWith(newBodyArg);
2885 extraMemRefArgs.push_back(newBodyArg);
2886 extraMemRefArgTypes.push_back(newBodyArg.getType());
2889 SmallVector<Type, 4> updatedCalleeArgTypes(
2890 callee.getFunctionType().getInputs());
2891 updatedCalleeArgTypes.append(extraMemRefArgTypes.begin(),
2892 extraMemRefArgTypes.end());
2893 callee.setType(FunctionType::get(callee.getContext(), updatedCalleeArgTypes,
2894 callee.getFunctionType().getResults()));
2896 unsigned otherArgsCount = 0;
2897 SmallVector<Value, 4> calleeArgFnOperands;
2898 builder.setInsertionPointToStart(callerEntryBlock);
2899 for (
auto arg : callee.getArguments().take_front(originalCalleeArgNum)) {
2900 if (isa<MemRefType>(arg.getType())) {
2901 auto memrefType = cast<MemRefType>(arg.getType());
2903 memref::AllocOp::create(builder, callee.getLoc(), memrefType);
2904 calleeArgFnOperands.push_back(allocOp);
2906 auto callerArg = callerEntryBlock->getArgument(otherArgsCount++);
2907 calleeArgFnOperands.push_back(callerArg);
2911 SmallVector<Value, 4> fnOperands;
2912 fnOperands.append(calleeArgFnOperands.begin(), calleeArgFnOperands.end());
2913 fnOperands.append(extraMemRefOperands.begin(), extraMemRefOperands.end());
2915 SymbolRefAttr::get(builder.getContext(), callee.getSymName());
2916 auto resultTypes = callee.getResultTypes();
2918 builder.setInsertionPointToEnd(callerEntryBlock);
2919 CallOp::create(builder, caller.getLoc(), calleeName, resultTypes,
2921 ReturnOp::create(builder, caller.getLoc());
2927 LogicalResult createOptNewTopLevelFn(ModuleOp moduleOp,
2928 std::string &topLevelFunction) {
2929 auto hasMemrefArguments = [](FuncOp func) {
2931 func.getArguments().begin(), func.getArguments().end(),
2932 [](BlockArgument arg) { return isa<MemRefType>(arg.getType()); });
2938 auto funcOps = moduleOp.getOps<FuncOp>();
2939 bool hasMemrefArgsInTopLevel =
2940 std::any_of(funcOps.begin(), funcOps.end(), [&](
auto funcOp) {
2941 return funcOp.getName() == topLevelFunction &&
2942 hasMemrefArguments(funcOp);
2945 if (hasMemrefArgsInTopLevel) {
2946 auto newTopLevelFunc = createNewTopLevelFn(moduleOp, topLevelFunction);
2947 if (!newTopLevelFunc)
2950 OpBuilder builder(moduleOp.getContext());
2951 Operation *oldTopLevelFuncOp =
2952 SymbolTable::lookupSymbolIn(moduleOp, topLevelFunction);
2953 if (
auto oldTopLevelFunc = dyn_cast<FuncOp>(oldTopLevelFuncOp))
2954 insertCallFromNewTopLevel(builder, newTopLevelFunc, oldTopLevelFunc);
2956 moduleOp.emitOpError(
"Original top-level function not found!");
2959 topLevelFunction =
"main";
2966void SCFToCalyxPass::runOnOperation() {
2971 std::string topLevelFunction;
2972 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
2973 signalPassFailure();
2978 if (failed(labelEntryPoint(topLevelFunction))) {
2979 signalPassFailure();
2982 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
2993 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
2994 SmallVector<LoweringPattern, 8> loweringPatterns;
2998 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
3002 addGreedyPattern<InlineExecuteRegionOpPattern>(loweringPatterns);
3005 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
3009 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
3012 addOncePattern<calyx::BuildCallInstance>(loweringPatterns, patternState,
3016 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
3022 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
3028 addOncePattern<BuildForGroups>(loweringPatterns, patternState, funcMap,
3031 addOncePattern<BuildIfGroups>(loweringPatterns, patternState, funcMap,
3041 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
3047 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
3052 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
3057 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
3063 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
3067 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
3072 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
3076 for (
auto &pat : loweringPatterns) {
3079 pat.strategy == LoweringPattern::Strategy::Once);
3082 signalPassFailure();
3089 RewritePatternSet cleanupPatterns(&getContext());
3093 applyPatternsGreedily(getOperation(), std::move(cleanupPatterns)))) {
3094 signalPassFailure();
3098 if (ciderSourceLocationMetadata) {
3101 SmallVector<Attribute, 16> sourceLocations;
3102 getOperation()->walk([&](calyx::ComponentOp component) {
3106 MLIRContext *context = getOperation()->getContext();
3107 getOperation()->setAttr(
"calyx.metadata",
3108 ArrayAttr::get(context, sourceLocations));
3117std::unique_ptr<OperationPass<ModuleOp>>
3119 return std::make_unique<SCFToCalyxPass>(topLevelFunction);
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...
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(std::string topLevelFunction="")
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.