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();
146 "A then group was already set for this scf::IfOp!\n");
151 auto it =
thenGroup.find(op.getOperation());
153 "No then group was set for this scf::IfOp!\n");
158 Operation *operation = op.getOperation();
160 "An else group was already set for this scf::IfOp!\n");
165 auto it =
elseGroup.find(op.getOperation());
167 "No else group was set for this scf::IfOp!\n");
173 "A register was already registered for the given yield result.\n");
174 assert(idx < op->getNumOperands());
184 auto it = regs.find(idx);
185 assert(it != regs.end() &&
"resultReg not found");
192 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
resultRegs;
202 OpBuilder &builder,
ScfWhileOp op, calyx::ComponentOp componentOp,
203 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
210 const DenseMap<unsigned, calyx::RegisterOp> &
221 SmallVector<calyx::GroupOp> groups) {
233 OpBuilder &builder,
ScfForOp op, calyx::ComponentOp componentOp,
234 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
281 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
283 mlir::Pass::Option<std::string> &writeJsonOpt)
286 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
290 PatternRewriter &rewriter)
const override {
293 bool opBuiltSuccessfully =
true;
294 funcOp.walk([&](Operation *_op) {
295 opBuiltSuccessfully &=
296 TypeSwitch<mlir::Operation *, bool>(_op)
298 arith::ConstantOp, ReturnOp, BranchOpInterface,
300 scf::YieldOp, scf::WhileOp, scf::ForOp, scf::IfOp,
301 scf::ParallelOp, scf::ReduceOp, scf::ExecuteRegionOp,
303 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
304 memref::StoreOp, memref::GetGlobalOp,
306 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp, AndIOp,
307 XOrIOp, OrIOp, ExtUIOp, ExtSIOp, TruncIOp, MulIOp, DivUIOp,
308 DivSIOp, RemUIOp, RemSIOp,
310 AddFOp, SubFOp, MulFOp, CmpFOp, FPToSIOp, SIToFPOp, DivFOp,
312 SelectOp, IndexCastOp, BitcastOp, CallOp>(
313 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
314 .
template Case<FuncOp, scf::ConditionOp>([&](
auto) {
318 .Default([&](
auto op) {
319 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
323 return opBuiltSuccessfully ? WalkResult::advance()
324 : WalkResult::interrupt();
328 if (
auto fileLoc = dyn_cast<mlir::FileLineColLoc>(funcOp->getLoc())) {
329 std::string filename = fileLoc.getFilename().str();
330 std::filesystem::path path(filename);
331 std::string jsonFileName =
writeJson.getValue() +
".json";
332 auto outFileName = path.parent_path().append(jsonFileName);
333 std::ofstream outFile(outFileName);
335 if (!outFile.is_open()) {
336 llvm::errs() <<
"Unable to open file: " << outFileName.string()
340 llvm::raw_os_ostream llvmOut(outFile);
341 llvm::json::OStream jsonOS(llvmOut, 2);
342 jsonOS.value(getState<ComponentLoweringState>().getExtMemData());
348 return success(opBuiltSuccessfully);
354 LogicalResult
buildOp(PatternRewriter &rewriter, scf::YieldOp yieldOp)
const;
355 LogicalResult
buildOp(PatternRewriter &rewriter,
356 BranchOpInterface brOp)
const;
357 LogicalResult
buildOp(PatternRewriter &rewriter,
358 arith::ConstantOp constOp)
const;
359 LogicalResult
buildOp(PatternRewriter &rewriter, SelectOp op)
const;
360 LogicalResult
buildOp(PatternRewriter &rewriter, AddIOp op)
const;
361 LogicalResult
buildOp(PatternRewriter &rewriter, SubIOp op)
const;
362 LogicalResult
buildOp(PatternRewriter &rewriter, MulIOp op)
const;
363 LogicalResult
buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
364 LogicalResult
buildOp(PatternRewriter &rewriter, DivSIOp op)
const;
365 LogicalResult
buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
366 LogicalResult
buildOp(PatternRewriter &rewriter, RemSIOp op)
const;
367 LogicalResult
buildOp(PatternRewriter &rewriter, AddFOp op)
const;
368 LogicalResult
buildOp(PatternRewriter &rewriter, SubFOp op)
const;
369 LogicalResult
buildOp(PatternRewriter &rewriter, MulFOp op)
const;
370 LogicalResult
buildOp(PatternRewriter &rewriter, CmpFOp op)
const;
371 LogicalResult
buildOp(PatternRewriter &rewriter, FPToSIOp op)
const;
372 LogicalResult
buildOp(PatternRewriter &rewriter, SIToFPOp op)
const;
373 LogicalResult
buildOp(PatternRewriter &rewriter, DivFOp op)
const;
374 LogicalResult
buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
375 LogicalResult
buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
376 LogicalResult
buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
377 LogicalResult
buildOp(PatternRewriter &rewriter, AndIOp op)
const;
378 LogicalResult
buildOp(PatternRewriter &rewriter, OrIOp op)
const;
379 LogicalResult
buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
380 LogicalResult
buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
381 LogicalResult
buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
382 LogicalResult
buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
383 LogicalResult
buildOp(PatternRewriter &rewriter, ExtSIOp op)
const;
384 LogicalResult
buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
385 LogicalResult
buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
386 LogicalResult
buildOp(PatternRewriter &rewriter, BitcastOp op)
const;
387 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
388 LogicalResult
buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
389 LogicalResult
buildOp(PatternRewriter &rewriter,
390 memref::GetGlobalOp op)
const;
391 LogicalResult
buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
392 LogicalResult
buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
393 LogicalResult
buildOp(PatternRewriter &rewriter, scf::WhileOp whileOp)
const;
394 LogicalResult
buildOp(PatternRewriter &rewriter, scf::ForOp forOp)
const;
395 LogicalResult
buildOp(PatternRewriter &rewriter, scf::IfOp ifOp)
const;
396 LogicalResult
buildOp(PatternRewriter &rewriter,
397 scf::ReduceOp reduceOp)
const;
398 LogicalResult
buildOp(PatternRewriter &rewriter,
399 scf::ParallelOp parallelOp)
const;
400 LogicalResult
buildOp(PatternRewriter &rewriter,
401 scf::ExecuteRegionOp executeRegionOp)
const;
402 LogicalResult
buildOp(PatternRewriter &rewriter, CallOp callOp)
const;
406 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
408 TypeRange srcTypes, TypeRange dstTypes)
const {
409 SmallVector<Type> types;
410 for (Type srcType : srcTypes)
412 for (Type dstType : dstTypes)
416 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
417 rewriter, op.getLoc(), types);
419 auto directions = calyxOp.portDirections();
420 SmallVector<Value, 4> opInputPorts;
421 SmallVector<Value, 4> opOutputPorts;
422 for (
auto dir : enumerate(directions)) {
424 opInputPorts.push_back(calyxOp.getResult(dir.index()));
426 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
429 opInputPorts.size() == op->getNumOperands() &&
430 opOutputPorts.size() == op->getNumResults() &&
431 "Expected an equal number of in/out ports in the Calyx library op with "
432 "respect to the number of operands/results of the source operation.");
435 auto group = createGroupForOp<TGroupOp>(rewriter, op);
436 rewriter.setInsertionPointToEnd(group.getBodyBlock());
437 for (
auto dstOp : enumerate(opInputPorts))
438 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(),
439 op->getOperand(dstOp.index()));
442 for (
auto res : enumerate(opOutputPorts)) {
443 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
445 op->getResult(res.index()).replaceAllUsesWith(res.value());
452 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
454 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
455 rewriter, op, op.getOperandTypes(), op->getResultTypes());
459 template <
typename TGroupOp>
461 Block *block = op->getBlock();
462 auto groupName = getState<ComponentLoweringState>().getUniqueName(
464 return calyx::createGroup<TGroupOp>(
465 rewriter, getState<ComponentLoweringState>().getComponentOp(),
466 op->getLoc(), groupName);
471 template <
typename TOpType,
typename TSrcOp>
473 TOpType opPipe, Value out)
const {
474 StringRef opName = TSrcOp::getOperationName().split(
".").second;
475 Location loc = op.getLoc();
476 Type width = op.getResult().getType();
477 auto reg = createRegister(
478 op.getLoc(), rewriter,
getComponent(), width.getIntOrFloatBitWidth(),
479 getState<ComponentLoweringState>().getUniqueName(opName));
481 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
482 OpBuilder builder(group->getRegion(0));
483 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
486 rewriter.setInsertionPointToEnd(group.getBodyBlock());
487 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
488 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
490 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), out);
492 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(), opPipe.getDone());
497 rewriter.create<calyx::AssignOp>(
498 loc, opPipe.getGo(), c1,
501 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
505 op.getResult().replaceAllUsesWith(reg.getOut());
507 if (isa<calyx::AddFOpIEEE754>(opPipe)) {
508 auto opFOp = cast<calyx::AddFOpIEEE754>(opPipe);
510 if (isa<arith::AddFOp>(op)) {
511 subOp = createConstant(loc, rewriter,
getComponent(), 1,
514 subOp = createConstant(loc, rewriter,
getComponent(), 1,
517 rewriter.create<calyx::AssignOp>(loc, opFOp.getSubOp(), subOp);
518 }
else if (
auto opFOp =
519 dyn_cast<calyx::DivSqrtOpIEEE754>(opPipe.getOperation())) {
520 bool isSqrt = !isa<arith::DivFOp>(op);
522 createConstant(loc, rewriter,
getComponent(), 1, isSqrt);
523 rewriter.create<calyx::AssignOp>(loc, opFOp.getSqrtOp(), sqrtOp);
527 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
528 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
530 getState<ComponentLoweringState>().registerEvaluatingGroup(
531 opPipe.getRight(), group);
536 template <
typename TCalyxLibOp,
typename TSrcOp>
538 unsigned inputWidth,
unsigned outputWidth,
539 StringRef signedPort)
const {
540 Location loc = op.getLoc();
541 IntegerType one = rewriter.getI1Type(),
542 inWidth = rewriter.getIntegerType(inputWidth),
543 outWidth = rewriter.getIntegerType(outputWidth);
545 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
546 rewriter, loc, {one, one, one, inWidth, one, outWidth, one});
548 StringRef opName = op.getOperationName().split(
".").second;
550 auto reg = createRegister(
551 loc, rewriter,
getComponent(), outWidth.getIntOrFloatBitWidth(),
552 getState<ComponentLoweringState>().getUniqueName(opName));
554 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
555 OpBuilder builder(group->getRegion(0));
556 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
559 rewriter.setInsertionPointToEnd(group.getBodyBlock());
560 rewriter.create<calyx::AssignOp>(loc, calyxOp.getIn(), op.getIn());
561 if (isa<calyx::FpToIntOpIEEE754>(calyxOp)) {
562 rewriter.create<calyx::AssignOp>(
563 loc, cast<calyx::FpToIntOpIEEE754>(calyxOp).getSignedOut(), c1);
564 }
else if (isa<calyx::IntToFpOpIEEE754>(calyxOp)) {
565 rewriter.create<calyx::AssignOp>(
566 loc, cast<calyx::IntToFpOpIEEE754>(calyxOp).getSignedIn(), c1);
568 op.getResult().replaceAllUsesWith(reg.getOut());
570 rewriter.create<calyx::AssignOp>(
571 loc, calyxOp.getGo(), c1,
573 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
581 calyx::GroupInterface group,
583 Operation::operand_range addressValues)
const {
584 IRRewriter::InsertionGuard guard(rewriter);
585 rewriter.setInsertionPointToEnd(group.getBody());
586 auto addrPorts = memoryInterface.
addrPorts();
587 if (addressValues.empty()) {
589 addrPorts.size() == 1 &&
590 "We expected a 1 dimensional memory of size 1 because there were no "
591 "address assignment values");
593 rewriter.create<calyx::AssignOp>(
597 assert(addrPorts.size() == addressValues.size() &&
598 "Mismatch between number of address ports of the provided memory "
599 "and address assignment values");
600 for (
auto address : enumerate(addressValues))
601 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
607 Value signal,
bool invert,
608 StringRef nameSuffix,
609 calyx::CompareFOpIEEE754 calyxCmpFOp,
610 calyx::GroupOp group)
const {
611 Location loc = calyxCmpFOp.getLoc();
612 IntegerType one = rewriter.getI1Type();
614 OpBuilder builder(group->getRegion(0));
615 auto reg = createRegister(
616 loc, rewriter, component, 1,
617 getState<ComponentLoweringState>().getUniqueName(nameSuffix));
618 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(),
619 calyxCmpFOp.getDone());
621 auto notLibOp = getState<ComponentLoweringState>()
622 .getNewLibraryOpInstance<calyx::NotLibOp>(
623 rewriter, loc, {one, one});
624 rewriter.create<calyx::AssignOp>(loc, notLibOp.getIn(), signal);
625 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), notLibOp.getOut());
626 getState<ComponentLoweringState>().registerEvaluatingGroup(
627 notLibOp.getOut(), group);
629 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), signal);
635 memref::LoadOp loadOp)
const {
636 Value memref = loadOp.getMemref();
637 auto memoryInterface =
638 getState<ComponentLoweringState>().getMemoryInterface(memref);
639 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
641 loadOp.getIndices());
643 rewriter.setInsertionPointToEnd(group.getBodyBlock());
648 createConstant(loadOp.getLoc(), rewriter,
getComponent(), 1, 1);
649 if (memoryInterface.readEnOpt().has_value()) {
652 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.readEn(),
654 regWriteEn = memoryInterface.done();
661 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
662 memoryInterface.done());
672 res = loadOp.getResult();
674 }
else if (memoryInterface.contentEnOpt().has_value()) {
679 rewriter.create<calyx::AssignOp>(loadOp.getLoc(),
680 memoryInterface.contentEn(), oneI1);
681 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.writeEn(),
683 regWriteEn = memoryInterface.done();
690 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
691 memoryInterface.done());
701 res = loadOp.getResult();
713 auto reg = createRegister(
715 loadOp.getMemRefType().getElementTypeBitWidth(),
716 getState<ComponentLoweringState>().getUniqueName(
"load"));
717 rewriter.setInsertionPointToEnd(group.getBodyBlock());
718 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), reg.getIn(),
719 memoryInterface.readData());
720 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), reg.getWriteEn(),
722 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(), reg.getDone());
723 loadOp.getResult().replaceAllUsesWith(reg.getOut());
727 getState<ComponentLoweringState>().registerEvaluatingGroup(res, group);
728 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
734 memref::StoreOp storeOp)
const {
735 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
736 storeOp.getMemref());
737 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
741 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
744 storeOp.getIndices());
745 rewriter.setInsertionPointToEnd(group.getBodyBlock());
746 rewriter.create<calyx::AssignOp>(
747 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
748 rewriter.create<calyx::AssignOp>(
749 storeOp.getLoc(), memoryInterface.writeEn(),
750 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
751 if (memoryInterface.contentEnOpt().has_value()) {
753 rewriter.create<calyx::AssignOp>(
754 storeOp.getLoc(), memoryInterface.contentEn(),
755 createConstant(storeOp.getLoc(), rewriter,
getComponent(), 1, 1));
757 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
764 Location loc = mul.getLoc();
765 Type width = mul.getResult().getType(), one = rewriter.getI1Type();
767 getState<ComponentLoweringState>()
768 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
769 rewriter, loc, {one, one, one, width, width, width, one});
770 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
771 rewriter, mul, mulPipe,
777 Location loc = div.getLoc();
778 Type width = div.getResult().getType(), one = rewriter.getI1Type();
780 getState<ComponentLoweringState>()
781 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
782 rewriter, loc, {one, one, one, width, width, width, one});
783 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
784 rewriter, div, divPipe,
790 Location loc = div.getLoc();
791 Type width = div.getResult().getType(), one = rewriter.getI1Type();
793 getState<ComponentLoweringState>()
794 .getNewLibraryOpInstance<calyx::DivSPipeLibOp>(
795 rewriter, loc, {one, one, one, width, width, width, one});
796 return buildLibraryBinaryPipeOp<calyx::DivSPipeLibOp>(
797 rewriter, div, divPipe,
803 Location loc = rem.getLoc();
804 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
806 getState<ComponentLoweringState>()
807 .getNewLibraryOpInstance<calyx::RemUPipeLibOp>(
808 rewriter, loc, {one, one, one, width, width, width, one});
809 return buildLibraryBinaryPipeOp<calyx::RemUPipeLibOp>(
810 rewriter, rem, remPipe,
816 Location loc = rem.getLoc();
817 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
819 getState<ComponentLoweringState>()
820 .getNewLibraryOpInstance<calyx::RemSPipeLibOp>(
821 rewriter, loc, {one, one, one, width, width, width, one});
822 return buildLibraryBinaryPipeOp<calyx::RemSPipeLibOp>(
823 rewriter, rem, remPipe,
829 Location loc = addf.getLoc();
830 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
831 five = rewriter.getIntegerType(5),
832 width = rewriter.getIntegerType(
833 addf.getType().getIntOrFloatBitWidth());
835 getState<ComponentLoweringState>()
836 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
838 {one, one, one, one, one, width, width, three, width, five, one});
839 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, addf, addFOp,
845 Location loc = subf.getLoc();
846 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
847 five = rewriter.getIntegerType(5),
848 width = rewriter.getIntegerType(
849 subf.getType().getIntOrFloatBitWidth());
851 getState<ComponentLoweringState>()
852 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
854 {one, one, one, one, one, width, width, three, width, five, one});
855 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, subf, subFOp,
861 Location loc = mulf.getLoc();
862 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
863 five = rewriter.getIntegerType(5),
864 width = rewriter.getIntegerType(
865 mulf.getType().getIntOrFloatBitWidth());
867 getState<ComponentLoweringState>()
868 .getNewLibraryOpInstance<calyx::MulFOpIEEE754>(
870 {one, one, one, one, width, width, three, width, five, one});
871 return buildLibraryBinaryPipeOp<calyx::MulFOpIEEE754>(rewriter, mulf, mulFOp,
877 Location loc = cmpf.getLoc();
878 IntegerType one = rewriter.getI1Type(), five = rewriter.getIntegerType(5),
879 width = rewriter.getIntegerType(
880 cmpf.getLhs().getType().getIntOrFloatBitWidth());
881 auto calyxCmpFOp = getState<ComponentLoweringState>()
882 .getNewLibraryOpInstance<calyx::CompareFOpIEEE754>(
884 {one, one, one, width, width, one, one, one, one,
891 using CombLogic = PredicateInfo::CombLogic;
892 using Port = PredicateInfo::InputPorts::Port;
894 if (info.logic == CombLogic::None) {
895 if (cmpf.getPredicate() == CmpFPredicate::AlwaysTrue) {
896 cmpf.getResult().replaceAllUsesWith(c1);
900 if (cmpf.getPredicate() == CmpFPredicate::AlwaysFalse) {
901 cmpf.getResult().replaceAllUsesWith(c0);
907 StringRef opName = cmpf.getOperationName().split(
".").second;
910 getState<ComponentLoweringState>().getUniqueName(opName));
913 auto group = createGroupForOp<calyx::GroupOp>(rewriter, cmpf);
914 OpBuilder builder(group->getRegion(0));
915 getState<ComponentLoweringState>().addBlockScheduleable(cmpf->getBlock(),
918 rewriter.setInsertionPointToEnd(group.getBodyBlock());
919 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getLeft(), cmpf.getLhs());
920 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getRight(), cmpf.getRhs());
922 bool signalingFlag =
false;
923 switch (cmpf.getPredicate()) {
924 case CmpFPredicate::UGT:
925 case CmpFPredicate::UGE:
926 case CmpFPredicate::ULT:
927 case CmpFPredicate::ULE:
928 case CmpFPredicate::OGT:
929 case CmpFPredicate::OGE:
930 case CmpFPredicate::OLT:
931 case CmpFPredicate::OLE:
932 signalingFlag =
true;
934 case CmpFPredicate::UEQ:
935 case CmpFPredicate::UNE:
936 case CmpFPredicate::OEQ:
937 case CmpFPredicate::ONE:
938 case CmpFPredicate::UNO:
939 case CmpFPredicate::ORD:
940 case CmpFPredicate::AlwaysTrue:
941 case CmpFPredicate::AlwaysFalse:
942 signalingFlag =
false;
948 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getSignaling(),
949 signalingFlag ? c1 : c0);
952 SmallVector<calyx::RegisterOp> inputRegs;
953 for (
const auto &input : info.inputPorts) {
955 switch (input.port) {
957 signal = calyxCmpFOp.getEq();
961 signal = calyxCmpFOp.getGt();
965 signal = calyxCmpFOp.getLt();
968 case Port::Unordered: {
969 signal = calyxCmpFOp.getUnordered();
973 std::string nameSuffix =
974 (input.port == PredicateInfo::InputPorts::Port::Unordered)
978 nameSuffix, calyxCmpFOp, group);
979 inputRegs.push_back(signalReg);
983 Value outputValue, doneValue;
984 switch (info.logic) {
985 case CombLogic::None: {
987 outputValue = inputRegs[0].getOut();
988 doneValue = inputRegs[0].getDone();
991 case CombLogic::And: {
992 auto outputLibOp = getState<ComponentLoweringState>()
993 .getNewLibraryOpInstance<calyx::AndLibOp>(
994 rewriter, loc, {one, one, one});
995 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
996 inputRegs[0].getOut());
997 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
998 inputRegs[1].getOut());
1000 outputValue = outputLibOp.getOut();
1003 case CombLogic::Or: {
1004 auto outputLibOp = getState<ComponentLoweringState>()
1005 .getNewLibraryOpInstance<calyx::OrLibOp>(
1006 rewriter, loc, {one, one, one});
1007 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
1008 inputRegs[0].getOut());
1009 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
1010 inputRegs[1].getOut());
1012 outputValue = outputLibOp.getOut();
1017 if (info.logic != CombLogic::None) {
1018 auto doneLibOp = getState<ComponentLoweringState>()
1019 .getNewLibraryOpInstance<calyx::AndLibOp>(
1020 rewriter, loc, {one, one, one});
1021 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getLeft(),
1022 inputRegs[0].getDone());
1023 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getRight(),
1024 inputRegs[1].getDone());
1025 doneValue = doneLibOp.getOut();
1029 rewriter.create<calyx::AssignOp>(loc, reg.getIn(), outputValue);
1030 rewriter.create<calyx::AssignOp>(loc, reg.getWriteEn(), doneValue);
1033 rewriter.create<calyx::AssignOp>(
1034 loc, calyxCmpFOp.getGo(), c1,
1036 rewriter.create<calyx::GroupDoneOp>(loc, reg.getDone());
1038 cmpf.getResult().replaceAllUsesWith(reg.getOut());
1041 getState<ComponentLoweringState>().registerEvaluatingGroup(outputValue,
1043 getState<ComponentLoweringState>().registerEvaluatingGroup(doneValue, group);
1044 getState<ComponentLoweringState>().registerEvaluatingGroup(
1045 calyxCmpFOp.getLeft(), group);
1046 getState<ComponentLoweringState>().registerEvaluatingGroup(
1047 calyxCmpFOp.getRight(), group);
1053 FPToSIOp fptosi)
const {
1054 return buildFpIntTypeCastOp<calyx::FpToIntOpIEEE754>(
1055 rewriter, fptosi, fptosi.getIn().getType().getIntOrFloatBitWidth(),
1056 fptosi.getOut().getType().getIntOrFloatBitWidth(),
"signedOut");
1060 SIToFPOp sitofp)
const {
1061 return buildFpIntTypeCastOp<calyx::IntToFpOpIEEE754>(
1062 rewriter, sitofp, sitofp.getIn().getType().getIntOrFloatBitWidth(),
1063 sitofp.getOut().getType().getIntOrFloatBitWidth(),
"signedIn");
1067 DivFOp divf)
const {
1068 Location loc = divf.getLoc();
1069 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
1070 five = rewriter.getIntegerType(5),
1071 width = rewriter.getIntegerType(
1072 divf.getType().getIntOrFloatBitWidth());
1073 auto divFOp = getState<ComponentLoweringState>()
1074 .getNewLibraryOpInstance<calyx::DivSqrtOpIEEE754>(
1078 width, three, width,
1080 return buildLibraryBinaryPipeOp<calyx::DivSqrtOpIEEE754>(
1081 rewriter, divf, divFOp, divFOp.getOut());
1084template <
typename TAllocOp>
1086 PatternRewriter &rewriter, TAllocOp allocOp) {
1087 rewriter.setInsertionPointToStart(
1089 MemRefType memtype = allocOp.getType();
1090 SmallVector<int64_t> addrSizes;
1091 SmallVector<int64_t> sizes;
1092 for (int64_t dim : memtype.getShape()) {
1093 sizes.push_back(dim);
1098 if (sizes.empty() && addrSizes.empty()) {
1100 addrSizes.push_back(1);
1102 auto memoryOp = rewriter.create<calyx::SeqMemoryOp>(
1104 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1108 memoryOp->setAttr(
"external",
1109 IntegerAttr::get(rewriter.getI1Type(), llvm::APInt(1, 1)));
1113 unsigned elmTyBitWidth = memtype.getElementTypeBitWidth();
1114 assert(elmTyBitWidth <= 64 &&
"element bitwidth should not exceed 64");
1115 bool isFloat = !memtype.getElementType().isInteger();
1117 auto shape = allocOp.getType().getShape();
1119 std::reduce(shape.begin(), shape.end(), 1, std::multiplies<int>());
1126 if (!(shape.size() <= 1 || totalSize <= 1)) {
1127 allocOp.emitError(
"input memory dimension must be empty or one.");
1131 std::vector<uint64_t> flattenedVals(totalSize, 0);
1132 if (isa<memref::GetGlobalOp>(allocOp)) {
1133 auto getGlobalOp = cast<memref::GetGlobalOp>(allocOp);
1134 auto *symbolTableOp =
1135 getGlobalOp->template getParentWithTrait<mlir::OpTrait::SymbolTable>();
1136 auto globalOp = dyn_cast_or_null<memref::GlobalOp>(
1137 SymbolTable::lookupSymbolIn(symbolTableOp, getGlobalOp.getNameAttr()));
1139 auto cstAttr = llvm::dyn_cast_or_null<DenseElementsAttr>(
1140 globalOp.getConstantInitValue());
1142 for (
auto attr : cstAttr.template getValues<Attribute>()) {
1143 assert((isa<mlir::FloatAttr, mlir::IntegerAttr>(attr)) &&
1144 "memory attributes must be float or int");
1145 if (
auto fltAttr = dyn_cast<mlir::FloatAttr>(attr)) {
1146 flattenedVals[sizeCount++] =
1147 bit_cast<uint64_t>(fltAttr.getValueAsDouble());
1149 auto intAttr = dyn_cast<mlir::IntegerAttr>(attr);
1150 APInt value = intAttr.getValue();
1151 flattenedVals[sizeCount++] = *value.getRawData();
1155 rewriter.eraseOp(globalOp);
1158 llvm::json::Array result;
1159 result.reserve(std::max(
static_cast<int>(shape.size()), 1));
1161 Type elemType = memtype.getElementType();
1163 !elemType.isSignlessInteger() && !elemType.isUnsignedInteger();
1164 for (uint64_t bitValue : flattenedVals) {
1165 llvm::json::Value value = 0;
1169 value = bit_cast<double>(bitValue);
1171 APInt apInt(elmTyBitWidth, bitValue, isSigned,
1176 value =
static_cast<int64_t
>(apInt.getSExtValue());
1178 value = apInt.getZExtValue();
1180 result.push_back(std::move(value));
1183 componentState.
setDataField(memoryOp.getName(), result);
1184 std::string numType =
1185 memtype.getElementType().isInteger() ?
"bitnum" :
"ieee754_float";
1186 componentState.
setFormat(memoryOp.getName(), numType, isSigned,
1193 memref::AllocOp allocOp)
const {
1194 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1198 memref::AllocaOp allocOp)
const {
1199 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1203 memref::GetGlobalOp getGlobalOp)
const {
1204 return buildAllocOp(getState<ComponentLoweringState>(), rewriter,
1209 scf::YieldOp yieldOp)
const {
1210 if (yieldOp.getOperands().empty()) {
1211 if (
auto forOp = dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1215 auto inductionReg = getState<ComponentLoweringState>().getForLoopIterReg(
1218 Type regWidth = inductionReg.getOut().getType();
1220 SmallVector<Type> types(3, regWidth);
1221 auto addOp = getState<ComponentLoweringState>()
1222 .getNewLibraryOpInstance<calyx::AddLibOp>(
1223 rewriter, forOp.getLoc(), types);
1225 auto directions = addOp.portDirections();
1227 SmallVector<Value, 2> opInputPorts;
1229 for (
auto dir : enumerate(directions)) {
1230 switch (dir.value()) {
1232 opInputPorts.push_back(addOp.getResult(dir.index()));
1236 opOutputPort = addOp.getResult(dir.index());
1244 getState<ComponentLoweringState>().getComponentOp();
1245 SmallVector<StringRef, 4> groupIdentifier = {
1246 "incr", getState<ComponentLoweringState>().getUniqueName(forOp),
1247 "induction",
"var"};
1248 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1250 llvm::join(groupIdentifier,
"_"));
1251 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
1254 Value leftOp = opInputPorts.front();
1255 rewriter.create<calyx::AssignOp>(forOp.getLoc(), leftOp,
1256 inductionReg.getOut());
1258 Value rightOp = opInputPorts.back();
1259 rewriter.create<calyx::AssignOp>(
1260 forOp.getLoc(), rightOp,
1261 createConstant(forOp->getLoc(), rewriter,
componentOp,
1262 regWidth.getIntOrFloatBitWidth(),
1263 forOp.getConstantStep().value().getSExtValue()));
1265 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp,
1266 inductionReg, opOutputPort);
1268 getState<ComponentLoweringState>().setForLoopLatchGroup(forOpInterface,
1270 getState<ComponentLoweringState>().registerEvaluatingGroup(opOutputPort,
1274 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp()))
1277 if (
auto executeRegionOp =
1278 dyn_cast<scf::ExecuteRegionOp>(yieldOp->getParentOp()))
1281 return yieldOp.getOperation()->emitError()
1282 <<
"Unsupported empty yieldOp outside ForOp or IfOp.";
1285 if (dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1286 return yieldOp.getOperation()->emitError()
1287 <<
"Currently do not support non-empty yield operations inside for "
1288 "loops. Run --scf-for-to-while before running --scf-to-calyx.";
1291 if (
auto whileOp = dyn_cast<scf::WhileOp>(yieldOp->getParentOp())) {
1295 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1296 rewriter, whileOpInterface,
1297 getState<ComponentLoweringState>().getComponentOp(),
1298 getState<ComponentLoweringState>().getUniqueName(whileOp) +
1300 yieldOp->getOpOperands());
1301 getState<ComponentLoweringState>().setWhileLoopLatchGroup(whileOpInterface,
1306 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp())) {
1307 auto resultRegs = getState<ComponentLoweringState>().getResultRegs(ifOp);
1309 if (yieldOp->getParentRegion() == &ifOp.getThenRegion()) {
1310 auto thenGroup = getState<ComponentLoweringState>().getThenGroup(ifOp);
1311 for (
auto op : enumerate(yieldOp.getOperands())) {
1313 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1314 buildAssignmentsForRegisterWrite(
1315 rewriter, thenGroup,
1316 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1318 getState<ComponentLoweringState>().registerEvaluatingGroup(
1319 ifOp.getResult(op.index()), thenGroup);
1323 if (!ifOp.getElseRegion().empty() &&
1324 (yieldOp->getParentRegion() == &ifOp.getElseRegion())) {
1325 auto elseGroup = getState<ComponentLoweringState>().getElseGroup(ifOp);
1326 for (
auto op : enumerate(yieldOp.getOperands())) {
1328 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1329 buildAssignmentsForRegisterWrite(
1330 rewriter, elseGroup,
1331 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1333 getState<ComponentLoweringState>().registerEvaluatingGroup(
1334 ifOp.getResult(op.index()), elseGroup);
1342 BranchOpInterface brOp)
const {
1347 Block *srcBlock = brOp->getBlock();
1348 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
1349 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
1350 if (succOperands.empty())
1355 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1356 brOp.getLoc(), groupName);
1358 auto dstBlockArgRegs =
1359 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
1361 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
1362 auto reg = dstBlockArgRegs[arg.index()];
1365 getState<ComponentLoweringState>().getComponentOp(), reg,
1370 getState<ComponentLoweringState>().addBlockArgGroup(
1371 srcBlock, succBlock.value(), groupOp);
1379 ReturnOp retOp)
const {
1380 if (retOp.getNumOperands() == 0)
1383 std::string groupName =
1384 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
1385 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter,
getComponent(),
1386 retOp.getLoc(), groupName);
1387 for (
auto op : enumerate(retOp.getOperands())) {
1388 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
1390 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
1394 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
1400 arith::ConstantOp constOp)
const {
1401 if (isa<IntegerType>(constOp.getType())) {
1410 std::string name = getState<ComponentLoweringState>().getUniqueName(
"cst");
1411 auto floatAttr = cast<FloatAttr>(constOp.getValueAttr());
1413 rewriter.getIntegerType(floatAttr.getType().getIntOrFloatBitWidth());
1414 auto calyxConstOp = rewriter.create<calyx::ConstantOp>(
1415 constOp.getLoc(), name, floatAttr, intType);
1418 rewriter.replaceAllUsesWith(constOp, calyxConstOp.getOut());
1426 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
1430 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
1434 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
1438 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
1442 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
1446 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
1450 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
1454 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
1457 SelectOp op)
const {
1458 return buildLibraryOp<calyx::CombGroupOp, calyx::MuxLibOp>(rewriter, op);
1463 switch (op.getPredicate()) {
1464 case CmpIPredicate::eq:
1465 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
1466 case CmpIPredicate::ne:
1467 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
1468 case CmpIPredicate::uge:
1469 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
1470 case CmpIPredicate::ult:
1471 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
1472 case CmpIPredicate::ugt:
1473 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
1474 case CmpIPredicate::ule:
1475 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
1476 case CmpIPredicate::sge:
1477 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
1478 case CmpIPredicate::slt:
1479 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
1480 case CmpIPredicate::sgt:
1481 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
1482 case CmpIPredicate::sle:
1483 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
1485 llvm_unreachable(
"unsupported comparison predicate");
1488 TruncIOp op)
const {
1489 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1490 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1494 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1495 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1500 return buildLibraryOp<calyx::CombGroupOp, calyx::ExtSILibOp>(
1501 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1505 IndexCastOp op)
const {
1508 unsigned targetBits = targetType.getIntOrFloatBitWidth();
1509 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
1510 LogicalResult res = success();
1512 if (targetBits == sourceBits) {
1515 op.getResult().replaceAllUsesWith(op.getOperand());
1518 if (sourceBits > targetBits)
1519 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1520 rewriter, op, {sourceType}, {targetType});
1522 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1523 rewriter, op, {sourceType}, {targetType});
1525 rewriter.eraseOp(op);
1532 BitcastOp op)
const {
1533 rewriter.replaceAllUsesWith(op.getOut(), op.getIn());
1538 scf::WhileOp whileOp)
const {
1542 getState<ComponentLoweringState>().addBlockScheduleable(
1548 scf::ForOp forOp)
const {
1554 std::optional<uint64_t> bound = scfForOp.
getBound();
1555 if (!bound.has_value()) {
1557 <<
"Loop bound not statically known. Should "
1558 "transform into while loop using `--scf-for-to-while` before "
1559 "running --lower-scf-to-calyx.";
1561 getState<ComponentLoweringState>().addBlockScheduleable(
1570 scf::IfOp ifOp)
const {
1571 getState<ComponentLoweringState>().addBlockScheduleable(
1577 scf::ReduceOp reduceOp)
const {
1585 scf::ParallelOp parOp)
const {
1588 "AffineParallelUnroll must be run in order to lower scf.parallel");
1591 getState<ComponentLoweringState>().addBlockScheduleable(
1598 scf::ExecuteRegionOp executeRegionOp)
const {
1606 CallOp callOp)
const {
1608 calyx::InstanceOp instanceOp =
1609 getState<ComponentLoweringState>().getInstance(instanceName);
1610 SmallVector<Value, 4> outputPorts;
1611 auto portInfos = instanceOp.getReferencedComponent().getPortInfo();
1612 for (
auto [idx, portInfo] : enumerate(portInfos)) {
1614 outputPorts.push_back(instanceOp.getResult(idx));
1618 for (
auto [idx, result] : llvm::enumerate(callOp.getResults()))
1619 rewriter.replaceAllUsesWith(result, outputPorts[idx]);
1623 getState<ComponentLoweringState>().addBlockScheduleable(
1637 using OpRewritePattern::OpRewritePattern;
1640 PatternRewriter &rewriter)
const override {
1641 if (
auto parOp = dyn_cast_or_null<scf::ParallelOp>(execOp->getParentOp())) {
1642 if (
auto boolAttr = dyn_cast_or_null<mlir::BoolAttr>(
1650 TypeRange yieldTypes = execOp.getResultTypes();
1654 rewriter.setInsertionPointAfter(execOp);
1655 auto *sinkBlock = rewriter.splitBlock(
1657 execOp.getOperation()->getIterator()->getNextNode()->getIterator());
1658 sinkBlock->addArguments(
1660 SmallVector<Location, 4>(yieldTypes.size(), rewriter.getUnknownLoc()));
1661 for (
auto res : enumerate(execOp.getResults()))
1662 res.value().replaceAllUsesWith(sinkBlock->getArgument(res.index()));
1666 make_early_inc_range(execOp.getRegion().getOps<scf::YieldOp>())) {
1667 rewriter.setInsertionPointAfter(yieldOp);
1668 rewriter.replaceOpWithNewOp<BranchOp>(yieldOp, sinkBlock,
1669 yieldOp.getOperands());
1673 auto *preBlock = execOp->getBlock();
1674 auto *execOpEntryBlock = &execOp.getRegion().front();
1675 auto *postBlock = execOp->getBlock()->splitBlock(execOp);
1676 rewriter.inlineRegionBefore(execOp.getRegion(), postBlock);
1677 rewriter.mergeBlocks(postBlock, preBlock);
1678 rewriter.eraseOp(execOp);
1681 rewriter.mergeBlocks(execOpEntryBlock, preBlock);
1689 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1693 PatternRewriter &rewriter)
const override {
1696 DenseMap<Value, unsigned> funcOpArgRewrites;
1700 DenseMap<unsigned, unsigned> funcOpResultMapping;
1708 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
1712 SmallVector<calyx::PortInfo> inPorts, outPorts;
1713 FunctionType funcType = funcOp.getFunctionType();
1714 for (
auto arg : enumerate(funcOp.getArguments())) {
1715 if (!isa<MemRefType>(arg.value().getType())) {
1718 if (
auto portNameAttr = funcOp.getArgAttrOfType<StringAttr>(
1720 inName = portNameAttr.str();
1722 inName =
"in" + std::to_string(arg.index());
1723 funcOpArgRewrites[arg.value()] = inPorts.size();
1725 rewriter.getStringAttr(inName),
1728 DictionaryAttr::get(rewriter.getContext(), {})});
1731 for (
auto res : enumerate(funcType.getResults())) {
1732 std::string resName;
1733 if (
auto portNameAttr = funcOp.getResultAttrOfType<StringAttr>(
1735 resName = portNameAttr.str();
1737 resName =
"out" + std::to_string(res.index());
1738 funcOpResultMapping[res.index()] = outPorts.size();
1741 rewriter.getStringAttr(resName),
1743 DictionaryAttr::get(rewriter.getContext(), {})});
1748 auto ports = inPorts;
1749 llvm::append_range(ports, outPorts);
1753 auto compOp = rewriter.create<calyx::ComponentOp>(
1754 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
1756 std::string funcName =
"func_" + funcOp.getSymName().str();
1757 rewriter.modifyOpInPlace(funcOp, [&]() { funcOp.setSymName(funcName); });
1762 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
1769 unsigned extMemCounter = 0;
1770 for (
auto arg : enumerate(funcOp.getArguments())) {
1771 if (isa<MemRefType>(arg.value().getType())) {
1772 std::string memName =
1773 llvm::join_items(
"_",
"arg_mem", std::to_string(extMemCounter++));
1775 rewriter.setInsertionPointToStart(compOp.getBodyBlock());
1776 MemRefType memtype = cast<MemRefType>(arg.value().getType());
1777 SmallVector<int64_t> addrSizes;
1778 SmallVector<int64_t> sizes;
1779 for (int64_t dim : memtype.getShape()) {
1780 sizes.push_back(dim);
1783 if (sizes.empty() && addrSizes.empty()) {
1785 addrSizes.push_back(1);
1787 auto memOp = rewriter.create<calyx::SeqMemoryOp>(
1788 funcOp.getLoc(), memName,
1789 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1792 compState->registerMemoryInterface(arg.value(),
1798 for (
auto &mapping : funcOpArgRewrites)
1799 mapping.getFirst().replaceAllUsesWith(
1800 compOp.getArgument(mapping.getSecond()));
1811 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1815 PatternRewriter &rewriter)
const override {
1816 LogicalResult res = success();
1817 funcOp.walk([&](Operation *op) {
1819 if (!isa<scf::WhileOp>(op))
1820 return WalkResult::advance();
1822 auto scfWhileOp = cast<scf::WhileOp>(op);
1825 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
1835 enumerate(scfWhileOp.getBefore().front().getArguments())) {
1836 auto condOp = scfWhileOp.getConditionOp().getArgs()[barg.index()];
1837 if (barg.value() != condOp) {
1841 <<
"do-while loops not supported; expected iter-args to "
1842 "remain untransformed in the 'before' region of the "
1844 return WalkResult::interrupt();
1853 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
1854 std::string name = getState<ComponentLoweringState>()
1857 "_arg" + std::to_string(arg.index());
1859 createRegister(arg.value().getLoc(), rewriter,
getComponent(),
1860 arg.value().getType().getIntOrFloatBitWidth(), name);
1861 getState<ComponentLoweringState>().addWhileLoopIterReg(whileOp, reg,
1863 arg.value().replaceAllUsesWith(reg.getOut());
1867 ->getArgument(arg.index())
1868 .replaceAllUsesWith(reg.getOut());
1872 SmallVector<calyx::GroupOp> initGroups;
1873 auto numOperands = whileOp.
getOperation()->getNumOperands();
1874 for (
size_t i = 0; i < numOperands; ++i) {
1876 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1878 getState<ComponentLoweringState>().getComponentOp(),
1879 getState<ComponentLoweringState>().getUniqueName(
1881 "_init_" + std::to_string(i),
1883 initGroups.push_back(initGroupOp);
1886 getState<ComponentLoweringState>().setWhileLoopInitGroups(whileOp,
1889 return WalkResult::advance();
1899 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1903 PatternRewriter &rewriter)
const override {
1904 LogicalResult res = success();
1905 funcOp.walk([&](Operation *op) {
1907 if (!isa<scf::ForOp>(op))
1908 return WalkResult::advance();
1910 auto scfForOp = cast<scf::ForOp>(op);
1913 getState<ComponentLoweringState>().setUniqueName(forOp.
getOperation(),
1918 auto inductionVar = forOp.
getOperation().getInductionVar();
1919 SmallVector<std::string, 3> inductionVarIdentifiers = {
1920 getState<ComponentLoweringState>()
1923 "induction",
"var"};
1924 std::string name = llvm::join(inductionVarIdentifiers,
"_");
1926 createRegister(inductionVar.getLoc(), rewriter,
getComponent(),
1927 inductionVar.getType().getIntOrFloatBitWidth(), name);
1928 getState<ComponentLoweringState>().addForLoopIterReg(forOp, reg, 0);
1929 inductionVar.replaceAllUsesWith(reg.getOut());
1933 getState<ComponentLoweringState>().getComponentOp();
1934 SmallVector<calyx::GroupOp> initGroups;
1935 SmallVector<std::string, 4> groupIdentifiers = {
1937 getState<ComponentLoweringState>()
1940 "induction",
"var"};
1941 std::string groupName = llvm::join(groupIdentifiers,
"_");
1942 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1944 buildAssignmentsForRegisterWrite(rewriter, groupOp,
componentOp, reg,
1946 initGroups.push_back(groupOp);
1947 getState<ComponentLoweringState>().setForLoopInitGroups(forOp,
1950 return WalkResult::advance();
1957 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1961 PatternRewriter &rewriter)
const override {
1962 LogicalResult res = success();
1963 funcOp.walk([&](Operation *op) {
1964 if (!isa<scf::IfOp>(op))
1965 return WalkResult::advance();
1967 auto scfIfOp = cast<scf::IfOp>(op);
1972 if (scfIfOp.getResults().empty())
1973 return WalkResult::advance();
1976 getState<ComponentLoweringState>().getComponentOp();
1978 std::string thenGroupName =
1979 getState<ComponentLoweringState>().getUniqueName(
"then_br");
1980 auto thenGroupOp = calyx::createGroup<calyx::GroupOp>(
1981 rewriter,
componentOp, scfIfOp.getLoc(), thenGroupName);
1982 getState<ComponentLoweringState>().setThenGroup(scfIfOp, thenGroupOp);
1984 if (!scfIfOp.getElseRegion().empty()) {
1985 std::string elseGroupName =
1986 getState<ComponentLoweringState>().getUniqueName(
"else_br");
1987 auto elseGroupOp = calyx::createGroup<calyx::GroupOp>(
1988 rewriter,
componentOp, scfIfOp.getLoc(), elseGroupName);
1989 getState<ComponentLoweringState>().setElseGroup(scfIfOp, elseGroupOp);
1992 for (
auto ifOpRes : scfIfOp.getResults()) {
1993 auto reg = createRegister(
1995 ifOpRes.getType().getIntOrFloatBitWidth(),
1996 getState<ComponentLoweringState>().getUniqueName(
"if_res"));
1997 getState<ComponentLoweringState>().setResultRegs(
1998 scfIfOp, reg, ifOpRes.getResultNumber());
2001 return WalkResult::advance();
2013 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2017 PatternRewriter &rewriter)
const override {
2018 auto *entryBlock = &funcOp.getBlocks().front();
2019 rewriter.setInsertionPointToStart(
2021 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
2022 DenseSet<Block *> path;
2024 nullptr, entryBlock);
2031 const DenseSet<Block *> &path,
2032 mlir::Block *parentCtrlBlock,
2033 mlir::Block *block)
const {
2034 auto compBlockScheduleables =
2035 getState<ComponentLoweringState>().getBlockScheduleables(block);
2036 auto loc = block->front().getLoc();
2038 if (compBlockScheduleables.size() > 1 &&
2039 !isa<scf::ParallelOp>(block->getParentOp())) {
2040 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
2041 parentCtrlBlock = seqOp.getBodyBlock();
2044 for (
auto &group : compBlockScheduleables) {
2045 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2046 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
2047 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
2048 groupPtr->getSymName());
2049 }
else if (
auto whileSchedPtr = std::get_if<WhileScheduleable>(&group);
2051 auto &whileOp = whileSchedPtr->whileOp;
2055 getState<ComponentLoweringState>().getWhileLoopInitGroups(whileOp),
2057 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
2059 rewriter.create<calyx::SeqOp>(whileOp.getOperation()->getLoc());
2060 auto *whileBodyOpBlock = whileBodyOp.getBodyBlock();
2064 if (LogicalResult result =
2066 whileOp.getBodyBlock());
2071 rewriter.setInsertionPointToEnd(whileBodyOpBlock);
2072 calyx::GroupOp whileLatchGroup =
2073 getState<ComponentLoweringState>().getWhileLoopLatchGroup(whileOp);
2074 rewriter.create<calyx::EnableOp>(whileLatchGroup.getLoc(),
2075 whileLatchGroup.getName());
2076 }
else if (
auto *parSchedPtr = std::get_if<ParScheduleable>(&group)) {
2077 auto parOp = parSchedPtr->parOp;
2078 auto calyxParOp = rewriter.create<calyx::ParOp>(parOp.getLoc());
2080 WalkResult walkResult =
2081 parOp.walk([&](scf::ExecuteRegionOp execRegion) {
2082 rewriter.setInsertionPointToEnd(calyxParOp.getBodyBlock());
2083 auto seqOp = rewriter.create<calyx::SeqOp>(execRegion.getLoc());
2084 rewriter.setInsertionPointToEnd(seqOp.getBodyBlock());
2086 for (
auto &execBlock : execRegion.getRegion().getBlocks()) {
2088 rewriter, path, seqOp.getBodyBlock(), &execBlock);
2090 return WalkResult::interrupt();
2093 return WalkResult::advance();
2096 if (walkResult.wasInterrupted())
2098 }
else if (
auto *forSchedPtr = std::get_if<ForScheduleable>(&group);
2100 auto forOp = forSchedPtr->forOp;
2104 getState<ComponentLoweringState>().getForLoopInitGroups(forOp),
2105 forSchedPtr->bound, rewriter);
2106 rewriter.setInsertionPointToEnd(forCtrlOp.getBodyBlock());
2108 rewriter.create<calyx::SeqOp>(forOp.getOperation()->getLoc());
2109 auto *forBodyOpBlock = forBodyOp.getBodyBlock();
2112 if (LogicalResult res =
buildCFGControl(path, rewriter, forBodyOpBlock,
2113 block, forOp.getBodyBlock());
2118 rewriter.setInsertionPointToEnd(forBodyOpBlock);
2119 calyx::GroupOp forLatchGroup =
2120 getState<ComponentLoweringState>().getForLoopLatchGroup(forOp);
2121 rewriter.create<calyx::EnableOp>(forLatchGroup.getLoc(),
2122 forLatchGroup.getName());
2123 }
else if (
auto *ifSchedPtr = std::get_if<IfScheduleable>(&group);
2125 auto ifOp = ifSchedPtr->ifOp;
2127 Location loc = ifOp->getLoc();
2129 auto cond = ifOp.getCondition();
2130 auto condGroup = getState<ComponentLoweringState>()
2131 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2133 auto symbolAttr = FlatSymbolRefAttr::get(
2134 StringAttr::get(getContext(), condGroup.getSymName()));
2136 bool initElse = !ifOp.getElseRegion().empty();
2137 auto ifCtrlOp = rewriter.create<calyx::IfOp>(
2138 loc, cond, symbolAttr, initElse);
2140 rewriter.setInsertionPointToEnd(ifCtrlOp.getBodyBlock());
2143 rewriter.create<calyx::SeqOp>(ifOp.getThenRegion().getLoc());
2144 auto *thenSeqOpBlock = thenSeqOp.getBodyBlock();
2146 auto *thenBlock = &ifOp.getThenRegion().front();
2154 if (!ifOp.getResults().empty()) {
2155 rewriter.setInsertionPointToEnd(thenSeqOpBlock);
2156 calyx::GroupOp thenGroup =
2157 getState<ComponentLoweringState>().getThenGroup(ifOp);
2158 rewriter.create<calyx::EnableOp>(thenGroup.getLoc(),
2159 thenGroup.getName());
2162 if (!ifOp.getElseRegion().empty()) {
2163 rewriter.setInsertionPointToEnd(ifCtrlOp.getElseBody());
2166 rewriter.create<calyx::SeqOp>(ifOp.getElseRegion().getLoc());
2167 auto *elseSeqOpBlock = elseSeqOp.getBodyBlock();
2169 auto *elseBlock = &ifOp.getElseRegion().front();
2175 if (!ifOp.getResults().empty()) {
2176 rewriter.setInsertionPointToEnd(elseSeqOpBlock);
2177 calyx::GroupOp elseGroup =
2178 getState<ComponentLoweringState>().getElseGroup(ifOp);
2179 rewriter.create<calyx::EnableOp>(elseGroup.getLoc(),
2180 elseGroup.getName());
2183 }
else if (
auto *callSchedPtr = std::get_if<CallScheduleable>(&group)) {
2184 auto instanceOp = callSchedPtr->instanceOp;
2185 OpBuilder::InsertionGuard g(rewriter);
2186 auto callBody = rewriter.create<calyx::SeqOp>(instanceOp.getLoc());
2187 rewriter.setInsertionPointToStart(callBody.getBodyBlock());
2189 auto callee = callSchedPtr->callOp.getCallee();
2190 auto *calleeOp = SymbolTable::lookupNearestSymbolFrom(
2191 callSchedPtr->callOp.getOperation()->getParentOp(),
2192 StringAttr::get(rewriter.getContext(),
"func_" + callee.str()));
2193 FuncOp calleeFunc = dyn_cast_or_null<FuncOp>(calleeOp);
2195 auto instanceOpComp =
2196 llvm::cast<calyx::ComponentOp>(instanceOp.getReferencedComponent());
2197 auto *instanceOpLoweringState =
2200 SmallVector<Value, 4> instancePorts;
2201 SmallVector<Value, 4> inputPorts;
2202 SmallVector<Attribute, 4> refCells;
2203 for (
auto operandEnum : enumerate(callSchedPtr->callOp.getOperands())) {
2204 auto operand = operandEnum.value();
2205 auto index = operandEnum.index();
2206 if (!isa<MemRefType>(operand.getType())) {
2207 inputPorts.push_back(operand);
2211 auto memOpName = getState<ComponentLoweringState>()
2212 .getMemoryInterface(operand)
2214 auto memOpNameAttr =
2215 SymbolRefAttr::get(rewriter.getContext(), memOpName);
2216 Value argI = calleeFunc.getArgument(index);
2217 if (isa<MemRefType>(argI.getType())) {
2218 NamedAttrList namedAttrList;
2219 namedAttrList.append(
2220 rewriter.getStringAttr(
2221 instanceOpLoweringState->getMemoryInterface(argI)
2225 DictionaryAttr::get(rewriter.getContext(), namedAttrList));
2228 llvm::copy(instanceOp.getResults().take_front(inputPorts.size()),
2229 std::back_inserter(instancePorts));
2231 ArrayAttr refCellsAttr =
2232 ArrayAttr::get(rewriter.getContext(), refCells);
2234 rewriter.create<calyx::InvokeOp>(
2235 instanceOp.getLoc(), instanceOp.getSymName(), instancePorts,
2236 inputPorts, refCellsAttr, ArrayAttr::get(rewriter.getContext(), {}),
2237 ArrayAttr::get(rewriter.getContext(), {}));
2239 llvm_unreachable(
"Unknown scheduleable");
2250 const DenseSet<Block *> &path, Location loc,
2251 Block *from, Block *to,
2252 Block *parentCtrlBlock)
const {
2255 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2256 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
2257 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
2259 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
2260 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
2266 PatternRewriter &rewriter,
2267 mlir::Block *parentCtrlBlock,
2268 mlir::Block *preBlock,
2269 mlir::Block *block)
const {
2270 if (path.count(block) != 0)
2271 return preBlock->getTerminator()->emitError()
2272 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
2273 "'scf.for' operations.";
2275 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2276 LogicalResult bbSchedResult =
2278 if (bbSchedResult.failed())
2279 return bbSchedResult;
2282 auto successors = block->getSuccessors();
2283 auto nSuccessors = successors.size();
2284 if (nSuccessors > 0) {
2285 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
2287 if (nSuccessors > 1) {
2291 assert(nSuccessors == 2 &&
2292 "only conditional branches supported for now...");
2294 auto cond = brOp->getOperand(0);
2295 auto condGroup = getState<ComponentLoweringState>()
2296 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2297 auto symbolAttr = FlatSymbolRefAttr::get(
2298 StringAttr::get(getContext(), condGroup.getSymName()));
2300 auto ifOp = rewriter.create<calyx::IfOp>(
2301 brOp->getLoc(), cond, symbolAttr,
true);
2302 rewriter.setInsertionPointToStart(ifOp.getThenBody());
2303 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2304 rewriter.setInsertionPointToStart(ifOp.getElseBody());
2305 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2307 bool trueBrSchedSuccess =
2308 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
2309 thenSeqOp.getBodyBlock())
2311 bool falseBrSchedSuccess =
true;
2312 if (trueBrSchedSuccess) {
2313 falseBrSchedSuccess =
2314 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
2315 elseSeqOp.getBodyBlock())
2319 return success(trueBrSchedSuccess && falseBrSchedSuccess);
2322 return schedulePath(rewriter, path, brOp.getLoc(), block,
2323 successors.front(), parentCtrlBlock);
2333 const SmallVector<calyx::GroupOp> &initGroups)
const {
2334 PatternRewriter::InsertionGuard g(rewriter);
2335 auto parOp = rewriter.create<calyx::ParOp>(loc);
2336 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
2337 for (calyx::GroupOp group : initGroups)
2338 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
2342 SmallVector<calyx::GroupOp> initGroups,
2343 PatternRewriter &rewriter)
const {
2344 Location loc = whileOp.
getLoc();
2351 auto condGroup = getState<ComponentLoweringState>()
2352 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2353 auto symbolAttr = FlatSymbolRefAttr::get(
2354 StringAttr::get(getContext(), condGroup.getSymName()));
2355 return rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
2359 SmallVector<calyx::GroupOp>
const &initGroups,
2361 PatternRewriter &rewriter)
const {
2362 Location loc = forOp.
getLoc();
2368 return rewriter.create<calyx::RepeatOp>(loc, bound);
2375 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2378 PatternRewriter &)
const override {
2379 funcOp.walk([&](scf::IfOp op) {
2380 for (
auto res : getState<ComponentLoweringState>().getResultRegs(op))
2381 op.getOperation()->getResults()[res.first].replaceAllUsesWith(
2382 res.second.getOut());
2385 funcOp.walk([&](scf::WhileOp op) {
2394 getState<ComponentLoweringState>().getWhileLoopIterRegs(whileOp))
2395 whileOp.
getOperation()->getResults()[res.first].replaceAllUsesWith(
2396 res.second.getOut());
2399 funcOp.walk([&](memref::LoadOp loadOp) {
2405 loadOp.getResult().replaceAllUsesWith(
2406 getState<ComponentLoweringState>()
2407 .getMemoryInterface(loadOp.getMemref())
2418 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2421 PatternRewriter &rewriter)
const override {
2422 rewriter.eraseOp(funcOp);
2428 PatternRewriter &rewriter)
const override {
2442class SCFToCalyxPass :
public circt::impl::SCFToCalyxBase<SCFToCalyxPass> {
2446 void runOnOperation()
override;
2448 LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp,
2449 std::string &topLevelFunction) {
2450 if (!topLevelFunctionOpt.empty()) {
2451 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
2453 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
2454 <<
"' not found in module.";
2457 topLevelFunction = topLevelFunctionOpt;
2461 auto funcOps = moduleOp.getOps<FuncOp>();
2462 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
2463 topLevelFunction = (*funcOps.begin()).getSymName().str();
2465 moduleOp.emitError()
2466 <<
"Module contains multiple functions, but no top level "
2467 "function was set. Please see --top-level-function";
2472 return createOptNewTopLevelFn(moduleOp, topLevelFunction);
2475 struct LoweringPattern {
2476 enum class Strategy { Once, Greedy };
2485 LogicalResult labelEntryPoint(StringRef topLevelFunction) {
2489 using OpRewritePattern::OpRewritePattern;
2490 LogicalResult matchAndRewrite(mlir::ModuleOp,
2491 PatternRewriter &)
const override {
2496 ConversionTarget target(getContext());
2497 target.addLegalDialect<calyx::CalyxDialect>();
2498 target.addLegalDialect<scf::SCFDialect>();
2499 target.addIllegalDialect<hw::HWDialect>();
2500 target.addIllegalDialect<comb::CombDialect>();
2503 target.addIllegalDialect<FuncDialect>();
2504 target.addIllegalDialect<ArithDialect>();
2505 target.addLegalOp<AddIOp, SelectOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp,
2506 ShRSIOp, AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp,
2507 CondBranchOp, BranchOp, MulIOp, DivUIOp, DivSIOp, RemUIOp,
2508 RemSIOp, ReturnOp, arith::ConstantOp, IndexCastOp,
2509 BitcastOp, FuncOp, ExtSIOp, CallOp, AddFOp, SubFOp,
2510 MulFOp, CmpFOp, FPToSIOp, SIToFPOp, DivFOp>();
2512 RewritePatternSet legalizePatterns(&getContext());
2513 legalizePatterns.add<DummyPattern>(&getContext());
2514 DenseSet<Operation *> legalizedOps;
2515 if (applyPartialConversion(getOperation(), target,
2516 std::move(legalizePatterns))
2527 template <
typename TPattern,
typename... PatternArgs>
2528 void addOncePattern(SmallVectorImpl<LoweringPattern> &
patterns,
2529 PatternArgs &&...args) {
2530 RewritePatternSet ps(&getContext());
2533 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Once});
2536 template <
typename TPattern,
typename... PatternArgs>
2537 void addGreedyPattern(SmallVectorImpl<LoweringPattern> &
patterns,
2538 PatternArgs &&...args) {
2539 RewritePatternSet ps(&getContext());
2540 ps.add<TPattern>(&getContext(), args...);
2542 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Greedy});
2545 LogicalResult runPartialPattern(RewritePatternSet &
pattern,
bool runOnce) {
2547 "Should only apply 1 partial lowering pattern at once");
2553 GreedyRewriteConfig config;
2554 config.enableRegionSimplification =
2555 mlir::GreedySimplifyRegionLevel::Disabled;
2557 config.maxIterations = 1;
2562 (void)applyPatternsGreedily(getOperation(), std::move(
pattern), config);
2571 FuncOp createNewTopLevelFn(ModuleOp moduleOp, std::string &baseName) {
2572 std::string newName =
"main";
2574 if (
auto *existingMainOp = SymbolTable::lookupSymbolIn(moduleOp, newName)) {
2575 auto existingMainFunc = dyn_cast<FuncOp>(existingMainOp);
2576 if (existingMainFunc ==
nullptr) {
2577 moduleOp.emitError() <<
"Symbol 'main' exists but is not a function";
2580 unsigned counter = 0;
2581 std::string newOldName = baseName;
2582 while (SymbolTable::lookupSymbolIn(moduleOp, newOldName))
2583 newOldName = llvm::join_items(
"_", baseName, std::to_string(++counter));
2584 existingMainFunc.setName(newOldName);
2585 if (baseName ==
"main")
2586 baseName = newOldName;
2590 OpBuilder builder(moduleOp.getContext());
2591 builder.setInsertionPointToStart(moduleOp.getBody());
2593 FunctionType funcType = builder.getFunctionType({}, {});
2596 builder.create<FuncOp>(moduleOp.getLoc(), newName, funcType))
2606 void insertCallFromNewTopLevel(OpBuilder &builder, FuncOp caller,
2608 if (caller.getBody().empty()) {
2609 caller.addEntryBlock();
2612 Block *callerEntryBlock = &caller.getBody().front();
2613 builder.setInsertionPointToStart(callerEntryBlock);
2617 SmallVector<Type, 4> nonMemRefCalleeArgTypes;
2618 for (
auto arg : callee.getArguments()) {
2619 if (!isa<MemRefType>(arg.getType())) {
2620 nonMemRefCalleeArgTypes.push_back(arg.getType());
2624 for (Type type : nonMemRefCalleeArgTypes) {
2625 callerEntryBlock->addArgument(type, caller.getLoc());
2628 FunctionType callerFnType = caller.getFunctionType();
2629 SmallVector<Type, 4> updatedCallerArgTypes(
2630 caller.getFunctionType().getInputs());
2631 updatedCallerArgTypes.append(nonMemRefCalleeArgTypes.begin(),
2632 nonMemRefCalleeArgTypes.end());
2633 caller.setType(FunctionType::get(caller.getContext(), updatedCallerArgTypes,
2634 callerFnType.getResults()));
2636 Block *calleeFnBody = &callee.getBody().front();
2637 unsigned originalCalleeArgNum = callee.getArguments().size();
2639 SmallVector<Value, 4> extraMemRefArgs;
2640 SmallVector<Type, 4> extraMemRefArgTypes;
2641 SmallVector<Value, 4> extraMemRefOperands;
2642 SmallVector<Operation *, 4> opsToModify;
2643 for (
auto &op : callee.getBody().getOps()) {
2644 if (isa<memref::AllocaOp, memref::AllocOp, memref::GetGlobalOp>(op))
2645 opsToModify.push_back(&op);
2650 builder.setInsertionPointToEnd(callerEntryBlock);
2651 for (
auto *op : opsToModify) {
2654 TypeSwitch<Operation *>(op)
2655 .Case<memref::AllocaOp>([&](memref::AllocaOp allocaOp) {
2656 newOpRes = builder.create<memref::AllocaOp>(callee.getLoc(),
2657 allocaOp.getType());
2659 .Case<memref::AllocOp>([&](memref::AllocOp allocOp) {
2660 newOpRes = builder.create<memref::AllocOp>(callee.getLoc(),
2663 .Case<memref::GetGlobalOp>([&](memref::GetGlobalOp getGlobalOp) {
2664 newOpRes = builder.create<memref::GetGlobalOp>(
2665 caller.getLoc(), getGlobalOp.getType(), getGlobalOp.getName());
2667 .Default([&](Operation *defaultOp) {
2668 llvm::report_fatal_error(
"Unsupported operation in TypeSwitch");
2670 extraMemRefOperands.push_back(newOpRes);
2672 calleeFnBody->addArgument(newOpRes.getType(), callee.getLoc());
2673 BlockArgument newBodyArg = calleeFnBody->getArguments().back();
2674 op->getResult(0).replaceAllUsesWith(newBodyArg);
2676 extraMemRefArgs.push_back(newBodyArg);
2677 extraMemRefArgTypes.push_back(newBodyArg.getType());
2680 SmallVector<Type, 4> updatedCalleeArgTypes(
2681 callee.getFunctionType().getInputs());
2682 updatedCalleeArgTypes.append(extraMemRefArgTypes.begin(),
2683 extraMemRefArgTypes.end());
2684 callee.setType(FunctionType::get(callee.getContext(), updatedCalleeArgTypes,
2685 callee.getFunctionType().getResults()));
2687 unsigned otherArgsCount = 0;
2688 SmallVector<Value, 4> calleeArgFnOperands;
2689 builder.setInsertionPointToStart(callerEntryBlock);
2690 for (
auto arg : callee.getArguments().take_front(originalCalleeArgNum)) {
2691 if (isa<MemRefType>(arg.getType())) {
2692 auto memrefType = cast<MemRefType>(arg.getType());
2694 builder.create<memref::AllocOp>(callee.getLoc(), memrefType);
2695 calleeArgFnOperands.push_back(allocOp);
2697 auto callerArg = callerEntryBlock->getArgument(otherArgsCount++);
2698 calleeArgFnOperands.push_back(callerArg);
2702 SmallVector<Value, 4> fnOperands;
2703 fnOperands.append(calleeArgFnOperands.begin(), calleeArgFnOperands.end());
2704 fnOperands.append(extraMemRefOperands.begin(), extraMemRefOperands.end());
2706 SymbolRefAttr::get(builder.getContext(), callee.getSymName());
2707 auto resultTypes = callee.getResultTypes();
2709 builder.setInsertionPointToEnd(callerEntryBlock);
2710 builder.create<CallOp>(caller.getLoc(), calleeName, resultTypes,
2712 builder.create<ReturnOp>(caller.getLoc());
2718 LogicalResult createOptNewTopLevelFn(ModuleOp moduleOp,
2719 std::string &topLevelFunction) {
2720 auto hasMemrefArguments = [](FuncOp func) {
2722 func.getArguments().begin(), func.getArguments().end(),
2723 [](BlockArgument arg) { return isa<MemRefType>(arg.getType()); });
2729 auto funcOps = moduleOp.getOps<FuncOp>();
2730 bool hasMemrefArgsInTopLevel =
2731 std::any_of(funcOps.begin(), funcOps.end(), [&](
auto funcOp) {
2732 return funcOp.getName() == topLevelFunction &&
2733 hasMemrefArguments(funcOp);
2736 if (hasMemrefArgsInTopLevel) {
2737 auto newTopLevelFunc = createNewTopLevelFn(moduleOp, topLevelFunction);
2738 if (!newTopLevelFunc)
2741 OpBuilder builder(moduleOp.getContext());
2742 Operation *oldTopLevelFuncOp =
2743 SymbolTable::lookupSymbolIn(moduleOp, topLevelFunction);
2744 if (
auto oldTopLevelFunc = dyn_cast<FuncOp>(oldTopLevelFuncOp))
2745 insertCallFromNewTopLevel(builder, newTopLevelFunc, oldTopLevelFunc);
2747 moduleOp.emitOpError(
"Original top-level function not found!");
2750 topLevelFunction =
"main";
2757void SCFToCalyxPass::runOnOperation() {
2762 std::string topLevelFunction;
2763 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
2764 signalPassFailure();
2769 if (failed(labelEntryPoint(topLevelFunction))) {
2770 signalPassFailure();
2773 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
2784 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
2785 SmallVector<LoweringPattern, 8> loweringPatterns;
2789 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
2793 addGreedyPattern<InlineExecuteRegionOpPattern>(loweringPatterns);
2796 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
2800 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
2803 addOncePattern<calyx::BuildCallInstance>(loweringPatterns, patternState,
2807 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
2813 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
2819 addOncePattern<BuildForGroups>(loweringPatterns, patternState, funcMap,
2822 addOncePattern<BuildIfGroups>(loweringPatterns, patternState, funcMap,
2832 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
2838 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
2843 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
2848 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
2854 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
2858 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
2863 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
2867 for (
auto &pat : loweringPatterns) {
2870 pat.strategy == LoweringPattern::Strategy::Once);
2873 signalPassFailure();
2880 RewritePatternSet cleanupPatterns(&getContext());
2884 applyPatternsGreedily(getOperation(), std::move(cleanupPatterns)))) {
2885 signalPassFailure();
2889 if (ciderSourceLocationMetadata) {
2892 SmallVector<Attribute, 16> sourceLocations;
2893 getOperation()->walk([&](calyx::ComponentOp component) {
2897 MLIRContext *context = getOperation()->getContext();
2898 getOperation()->setAttr(
"calyx.metadata",
2899 ArrayAttr::get(context, sourceLocations));
2909 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 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
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::GroupOp getThenGroup(scf::IfOp op)
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
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)
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.