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"
50 using namespace mlir::arith;
51 using namespace mlir::cf;
54 class ComponentLoweringStateInterface;
55 namespace scftocalyx {
64 : calyx::WhileOpInterface<scf::WhileOp>(op) {}
67 return getOperation().getAfterArguments();
70 Block *
getBodyBlock()
override {
return &getOperation().getAfter().front(); }
73 return &getOperation().getBefore().front();
77 return getOperation().getConditionOp().getOperand(0);
80 std::optional<int64_t>
getBound()
override {
return std::nullopt; }
85 explicit ScfForOp(scf::ForOp op) : calyx::RepeatOpInterface<scf::ForOp>(op) {}
88 return getOperation().getRegion().getArguments();
92 return &getOperation().getRegion().getBlocks().front();
96 return constantTripCount(getOperation().getLowerBound(),
97 getOperation().getUpperBound(),
98 getOperation().getStep());
142 Operation *operation = op.getOperation();
143 assert(thenGroup.count(operation) == 0 &&
144 "A then group was already set for this scf::IfOp!\n");
145 thenGroup[operation] = group;
149 auto it = thenGroup.find(op.getOperation());
150 assert(it != thenGroup.end() &&
151 "No then group was set for this scf::IfOp!\n");
156 Operation *operation = op.getOperation();
157 assert(elseGroup.count(operation) == 0 &&
158 "An else group was already set for this scf::IfOp!\n");
159 elseGroup[operation] = group;
163 auto it = elseGroup.find(op.getOperation());
164 assert(it != elseGroup.end() &&
165 "No else group was set for this scf::IfOp!\n");
170 assert(resultRegs[op.getOperation()].count(idx) == 0 &&
171 "A register was already registered for the given yield result.\n");
172 assert(idx < op->getNumOperands());
173 resultRegs[op.getOperation()][idx] =
reg;
177 return resultRegs[op.getOperation()];
181 auto regs = getResultRegs(op);
182 auto it = regs.find(idx);
183 assert(it != regs.end() &&
"resultReg not found");
190 DenseMap<Operation *, DenseMap<unsigned, calyx::RegisterOp>>
resultRegs;
197 return getLoopInitGroups(std::move(op));
200 OpBuilder &builder,
ScfWhileOp op, calyx::ComponentOp componentOp,
201 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
202 return buildLoopIterArgAssignments(builder, std::move(op), componentOp,
206 return addLoopIterReg(std::move(op),
reg, idx);
208 const DenseMap<unsigned, calyx::RegisterOp> &
210 return getLoopIterRegs(std::move(op));
213 return setLoopLatchGroup(std::move(op), group);
216 return getLoopLatchGroup(std::move(op));
219 SmallVector<calyx::GroupOp> groups) {
220 return setLoopInitGroups(std::move(op), std::move(groups));
228 return getLoopInitGroups(std::move(op));
231 OpBuilder &builder,
ScfForOp op, calyx::ComponentOp componentOp,
232 Twine uniqueSuffix, MutableArrayRef<OpOperand> ops) {
233 return buildLoopIterArgAssignments(builder, std::move(op), componentOp,
237 return addLoopIterReg(std::move(op),
reg, idx);
240 return getLoopIterRegs(std::move(op));
243 return getLoopIterReg(std::move(op), idx);
246 return setLoopLatchGroup(std::move(op), group);
249 return getLoopLatchGroup(std::move(op));
252 return setLoopInitGroups(std::move(op), std::move(groups));
266 : calyx::ComponentLoweringStateInterface(component) {}
279 DenseMap<mlir::func::FuncOp, calyx::ComponentOp> &map,
281 mlir::Pass::Option<std::string> &writeJsonOpt)
282 : FuncOpPartialLoweringPattern(context, resRef, patternState, map, state),
283 writeJson(writeJsonOpt) {}
284 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
288 PatternRewriter &rewriter)
const override {
291 bool opBuiltSuccessfully =
true;
292 funcOp.walk([&](Operation *_op) {
293 opBuiltSuccessfully &=
294 TypeSwitch<mlir::Operation *, bool>(_op)
295 .template Case<arith::ConstantOp, ReturnOp, BranchOpInterface,
297 scf::YieldOp, scf::WhileOp, scf::ForOp, scf::IfOp,
298 scf::ParallelOp, scf::ReduceOp,
300 memref::AllocOp, memref::AllocaOp, memref::LoadOp,
301 memref::StoreOp, memref::GetGlobalOp,
303 AddIOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp, ShRSIOp,
304 AndIOp, XOrIOp, OrIOp, ExtUIOp, ExtSIOp, TruncIOp,
305 MulIOp, DivUIOp, DivSIOp, RemUIOp, RemSIOp,
307 AddFOp, MulFOp, CmpFOp,
309 SelectOp, IndexCastOp, CallOp>(
310 [&](
auto op) {
return buildOp(rewriter, op).succeeded(); })
311 .
template Case<FuncOp, scf::ConditionOp>([&](
auto) {
315 .Default([&](
auto op) {
316 op->emitError() <<
"Unhandled operation during BuildOpGroups()";
320 return opBuiltSuccessfully ? WalkResult::advance()
321 : WalkResult::interrupt();
324 if (!writeJson.empty()) {
325 if (
auto fileLoc = dyn_cast<mlir::FileLineColLoc>(funcOp->getLoc())) {
326 std::string filename = fileLoc.getFilename().str();
327 std::filesystem::path path(filename);
328 std::string jsonFileName = writeJson.getValue() +
".json";
329 auto outFileName = path.parent_path().append(jsonFileName);
330 std::ofstream outFile(outFileName);
332 if (!outFile.is_open()) {
333 llvm::errs() <<
"Unable to open file: " << outFileName.string()
337 llvm::raw_os_ostream llvmOut(outFile);
338 llvm::json::OStream jsonOS(llvmOut, 2);
339 jsonOS.value(getState<ComponentLoweringState>().getExtMemData());
345 return success(opBuiltSuccessfully);
351 LogicalResult buildOp(PatternRewriter &rewriter, scf::YieldOp yieldOp)
const;
352 LogicalResult buildOp(PatternRewriter &rewriter,
353 BranchOpInterface brOp)
const;
354 LogicalResult buildOp(PatternRewriter &rewriter,
355 arith::ConstantOp constOp)
const;
356 LogicalResult buildOp(PatternRewriter &rewriter, SelectOp op)
const;
357 LogicalResult buildOp(PatternRewriter &rewriter, AddIOp op)
const;
358 LogicalResult buildOp(PatternRewriter &rewriter, SubIOp op)
const;
359 LogicalResult buildOp(PatternRewriter &rewriter, MulIOp op)
const;
360 LogicalResult buildOp(PatternRewriter &rewriter, DivUIOp op)
const;
361 LogicalResult buildOp(PatternRewriter &rewriter, DivSIOp op)
const;
362 LogicalResult buildOp(PatternRewriter &rewriter, RemUIOp op)
const;
363 LogicalResult buildOp(PatternRewriter &rewriter, RemSIOp op)
const;
364 LogicalResult buildOp(PatternRewriter &rewriter, AddFOp op)
const;
365 LogicalResult buildOp(PatternRewriter &rewriter, MulFOp op)
const;
366 LogicalResult buildOp(PatternRewriter &rewriter, CmpFOp op)
const;
367 LogicalResult buildOp(PatternRewriter &rewriter, ShRUIOp op)
const;
368 LogicalResult buildOp(PatternRewriter &rewriter, ShRSIOp op)
const;
369 LogicalResult buildOp(PatternRewriter &rewriter, ShLIOp op)
const;
370 LogicalResult buildOp(PatternRewriter &rewriter, AndIOp op)
const;
371 LogicalResult buildOp(PatternRewriter &rewriter, OrIOp op)
const;
372 LogicalResult buildOp(PatternRewriter &rewriter, XOrIOp op)
const;
373 LogicalResult buildOp(PatternRewriter &rewriter, CmpIOp op)
const;
374 LogicalResult buildOp(PatternRewriter &rewriter, TruncIOp op)
const;
375 LogicalResult buildOp(PatternRewriter &rewriter, ExtUIOp op)
const;
376 LogicalResult buildOp(PatternRewriter &rewriter, ExtSIOp op)
const;
377 LogicalResult buildOp(PatternRewriter &rewriter, ReturnOp op)
const;
378 LogicalResult buildOp(PatternRewriter &rewriter, IndexCastOp op)
const;
379 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocOp op)
const;
380 LogicalResult buildOp(PatternRewriter &rewriter, memref::AllocaOp op)
const;
381 LogicalResult buildOp(PatternRewriter &rewriter,
382 memref::GetGlobalOp op)
const;
383 LogicalResult buildOp(PatternRewriter &rewriter, memref::LoadOp op)
const;
384 LogicalResult buildOp(PatternRewriter &rewriter, memref::StoreOp op)
const;
385 LogicalResult buildOp(PatternRewriter &rewriter, scf::WhileOp whileOp)
const;
386 LogicalResult buildOp(PatternRewriter &rewriter, scf::ForOp forOp)
const;
387 LogicalResult buildOp(PatternRewriter &rewriter, scf::IfOp ifOp)
const;
388 LogicalResult buildOp(PatternRewriter &rewriter,
389 scf::ReduceOp reduceOp)
const;
390 LogicalResult buildOp(PatternRewriter &rewriter,
391 scf::ParallelOp parallelOp)
const;
392 LogicalResult buildOp(PatternRewriter &rewriter, CallOp callOp)
const;
396 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
398 TypeRange srcTypes, TypeRange dstTypes)
const {
399 SmallVector<Type> types;
400 for (Type srcType : srcTypes)
402 for (Type dstType : dstTypes)
406 getState<ComponentLoweringState>().getNewLibraryOpInstance<TCalyxLibOp>(
407 rewriter, op.getLoc(), types);
409 auto directions = calyxOp.portDirections();
410 SmallVector<Value, 4> opInputPorts;
411 SmallVector<Value, 4> opOutputPorts;
412 for (
auto dir : enumerate(directions)) {
414 opInputPorts.push_back(calyxOp.getResult(dir.index()));
416 opOutputPorts.push_back(calyxOp.getResult(dir.index()));
419 opInputPorts.size() == op->getNumOperands() &&
420 opOutputPorts.size() == op->getNumResults() &&
421 "Expected an equal number of in/out ports in the Calyx library op with "
422 "respect to the number of operands/results of the source operation.");
425 auto group = createGroupForOp<TGroupOp>(rewriter, op);
426 rewriter.setInsertionPointToEnd(group.getBodyBlock());
427 for (
auto dstOp : enumerate(opInputPorts))
428 rewriter.create<calyx::AssignOp>(op.getLoc(), dstOp.value(),
429 op->getOperand(dstOp.index()));
432 for (
auto res : enumerate(opOutputPorts)) {
433 getState<ComponentLoweringState>().registerEvaluatingGroup(res.value(),
435 op->getResult(res.index()).replaceAllUsesWith(res.value());
442 template <
typename TGroupOp,
typename TCalyxLibOp,
typename TSrcOp>
444 return buildLibraryOp<TGroupOp, TCalyxLibOp, TSrcOp>(
445 rewriter, op, op.getOperandTypes(), op->getResultTypes());
449 template <
typename TGroupOp>
451 Block *block = op->getBlock();
452 auto groupName = getState<ComponentLoweringState>().getUniqueName(
454 return calyx::createGroup<TGroupOp>(
455 rewriter, getState<ComponentLoweringState>().getComponentOp(),
456 op->getLoc(), groupName);
461 template <
typename TOpType,
typename TSrcOp>
463 TOpType opPipe, Value out)
const {
464 StringRef opName = TSrcOp::getOperationName().split(
".").second;
465 Location loc = op.getLoc();
466 Type width = op.getResult().getType();
468 op.getLoc(), rewriter, getComponent(), width.getIntOrFloatBitWidth(),
469 getState<ComponentLoweringState>().getUniqueName(opName));
471 auto group = createGroupForOp<calyx::GroupOp>(rewriter, op);
472 OpBuilder builder(group->getRegion(0));
473 getState<ComponentLoweringState>().addBlockScheduleable(op->getBlock(),
476 rewriter.setInsertionPointToEnd(group.getBodyBlock());
477 rewriter.create<calyx::AssignOp>(loc, opPipe.getLeft(), op.getLhs());
478 rewriter.create<calyx::AssignOp>(loc, opPipe.getRight(), op.getRhs());
480 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), out);
482 rewriter.create<calyx::AssignOp>(loc,
reg.getWriteEn(), opPipe.getDone());
487 rewriter.create<calyx::AssignOp>(
488 loc, opPipe.getGo(), c1,
491 rewriter.create<calyx::GroupDoneOp>(loc,
reg.getDone());
495 op.getResult().replaceAllUsesWith(
reg.getOut());
497 if (isa<calyx::AddFOpIEEE754>(opPipe)) {
498 auto opFOp = cast<calyx::AddFOpIEEE754>(opPipe);
500 if (isa<arith::AddFOp>(op)) {
507 rewriter.create<calyx::AssignOp>(loc, opFOp.getSubOp(), subOp);
511 getState<ComponentLoweringState>().registerEvaluatingGroup(out, group);
512 getState<ComponentLoweringState>().registerEvaluatingGroup(opPipe.getLeft(),
514 getState<ComponentLoweringState>().registerEvaluatingGroup(
515 opPipe.getRight(), group);
523 calyx::GroupInterface group,
525 Operation::operand_range addressValues)
const {
526 IRRewriter::InsertionGuard guard(rewriter);
527 rewriter.setInsertionPointToEnd(group.getBody());
528 auto addrPorts = memoryInterface.
addrPorts();
529 if (addressValues.empty()) {
531 addrPorts.size() == 1 &&
532 "We expected a 1 dimensional memory of size 1 because there were no "
533 "address assignment values");
535 rewriter.create<calyx::AssignOp>(
539 assert(addrPorts.size() == addressValues.size() &&
540 "Mismatch between number of address ports of the provided memory "
541 "and address assignment values");
542 for (
auto address : enumerate(addressValues))
543 rewriter.create<calyx::AssignOp>(loc, addrPorts[address.index()],
549 Value signal,
bool invert,
550 StringRef nameSuffix,
551 calyx::CompareFOpIEEE754 calyxCmpFOp,
552 calyx::GroupOp group)
const {
553 Location loc = calyxCmpFOp.getLoc();
554 IntegerType one = rewriter.getI1Type();
555 auto component = getComponent();
556 OpBuilder builder(group->getRegion(0));
558 loc, rewriter, component, 1,
559 getState<ComponentLoweringState>().getUniqueName(nameSuffix));
560 rewriter.create<calyx::AssignOp>(loc,
reg.getWriteEn(),
561 calyxCmpFOp.getDone());
563 auto notLibOp = getState<ComponentLoweringState>()
564 .getNewLibraryOpInstance<calyx::NotLibOp>(
565 rewriter, loc, {one, one});
566 rewriter.create<calyx::AssignOp>(loc, notLibOp.getIn(), signal);
567 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), notLibOp.getOut());
568 getState<ComponentLoweringState>().registerEvaluatingGroup(
569 notLibOp.getOut(), group);
571 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), signal);
576 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
577 memref::LoadOp loadOp)
const {
578 Value memref = loadOp.getMemref();
579 auto memoryInterface =
580 getState<ComponentLoweringState>().getMemoryInterface(memref);
581 auto group = createGroupForOp<calyx::GroupOp>(rewriter, loadOp);
582 assignAddressPorts(rewriter, loadOp.getLoc(), group, memoryInterface,
583 loadOp.getIndices());
585 rewriter.setInsertionPointToEnd(group.getBodyBlock());
591 if (memoryInterface.readEnOpt().has_value()) {
594 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.readEn(),
596 regWriteEn = memoryInterface.done();
603 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
604 memoryInterface.done());
614 res = loadOp.getResult();
616 }
else if (memoryInterface.contentEnOpt().has_value()) {
621 rewriter.create<calyx::AssignOp>(loadOp.getLoc(),
622 memoryInterface.contentEn(), oneI1);
623 rewriter.create<calyx::AssignOp>(loadOp.getLoc(), memoryInterface.writeEn(),
625 regWriteEn = memoryInterface.done();
632 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
633 memoryInterface.done());
643 res = loadOp.getResult();
656 loadOp.getLoc(), rewriter, getComponent(),
657 loadOp.getMemRefType().getElementTypeBitWidth(),
658 getState<ComponentLoweringState>().getUniqueName(
"load"));
659 rewriter.setInsertionPointToEnd(group.getBodyBlock());
660 rewriter.create<calyx::AssignOp>(loadOp.getLoc(),
reg.getIn(),
661 memoryInterface.readData());
662 rewriter.create<calyx::AssignOp>(loadOp.getLoc(),
reg.getWriteEn(),
664 rewriter.create<calyx::GroupDoneOp>(loadOp.getLoc(),
reg.getDone());
665 loadOp.getResult().replaceAllUsesWith(
reg.getOut());
669 getState<ComponentLoweringState>().registerEvaluatingGroup(res, group);
670 getState<ComponentLoweringState>().addBlockScheduleable(loadOp->getBlock(),
675 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
676 memref::StoreOp storeOp)
const {
677 auto memoryInterface = getState<ComponentLoweringState>().getMemoryInterface(
678 storeOp.getMemref());
679 auto group = createGroupForOp<calyx::GroupOp>(rewriter, storeOp);
683 getState<ComponentLoweringState>().addBlockScheduleable(storeOp->getBlock(),
685 assignAddressPorts(rewriter, storeOp.getLoc(), group, memoryInterface,
686 storeOp.getIndices());
687 rewriter.setInsertionPointToEnd(group.getBodyBlock());
688 rewriter.create<calyx::AssignOp>(
689 storeOp.getLoc(), memoryInterface.writeData(), storeOp.getValueToStore());
690 rewriter.create<calyx::AssignOp>(
691 storeOp.getLoc(), memoryInterface.writeEn(),
692 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
693 if (memoryInterface.contentEnOpt().has_value()) {
695 rewriter.create<calyx::AssignOp>(
696 storeOp.getLoc(), memoryInterface.contentEn(),
697 createConstant(storeOp.getLoc(), rewriter, getComponent(), 1, 1));
699 rewriter.create<calyx::GroupDoneOp>(storeOp.getLoc(), memoryInterface.done());
704 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
706 Location loc = mul.getLoc();
707 Type width = mul.getResult().getType(), one = rewriter.getI1Type();
709 getState<ComponentLoweringState>()
710 .getNewLibraryOpInstance<calyx::MultPipeLibOp>(
711 rewriter, loc, {one, one, one, width, width, width, one});
712 return buildLibraryBinaryPipeOp<calyx::MultPipeLibOp>(
713 rewriter, mul, mulPipe,
717 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
719 Location loc = div.getLoc();
720 Type width = div.getResult().getType(), one = rewriter.getI1Type();
722 getState<ComponentLoweringState>()
723 .getNewLibraryOpInstance<calyx::DivUPipeLibOp>(
724 rewriter, loc, {one, one, one, width, width, width, one});
725 return buildLibraryBinaryPipeOp<calyx::DivUPipeLibOp>(
726 rewriter, div, divPipe,
730 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
732 Location loc = div.getLoc();
733 Type width = div.getResult().getType(), one = rewriter.getI1Type();
735 getState<ComponentLoweringState>()
736 .getNewLibraryOpInstance<calyx::DivSPipeLibOp>(
737 rewriter, loc, {one, one, one, width, width, width, one});
738 return buildLibraryBinaryPipeOp<calyx::DivSPipeLibOp>(
739 rewriter, div, divPipe,
743 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
745 Location loc = rem.getLoc();
746 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
748 getState<ComponentLoweringState>()
749 .getNewLibraryOpInstance<calyx::RemUPipeLibOp>(
750 rewriter, loc, {one, one, one, width, width, width, one});
751 return buildLibraryBinaryPipeOp<calyx::RemUPipeLibOp>(
752 rewriter, rem, remPipe,
756 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
758 Location loc = rem.getLoc();
759 Type width = rem.getResult().getType(), one = rewriter.getI1Type();
761 getState<ComponentLoweringState>()
762 .getNewLibraryOpInstance<calyx::RemSPipeLibOp>(
763 rewriter, loc, {one, one, one, width, width, width, one});
764 return buildLibraryBinaryPipeOp<calyx::RemSPipeLibOp>(
765 rewriter, rem, remPipe,
769 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
771 Location loc = addf.getLoc();
772 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
773 five = rewriter.getIntegerType(5),
774 width = rewriter.getIntegerType(
775 addf.getType().getIntOrFloatBitWidth());
777 getState<ComponentLoweringState>()
778 .getNewLibraryOpInstance<calyx::AddFOpIEEE754>(
780 {one, one, one, one, one, width, width, three, width, five, one});
781 return buildLibraryBinaryPipeOp<calyx::AddFOpIEEE754>(rewriter, addf, addFOp,
785 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
787 Location loc = mulf.getLoc();
788 IntegerType one = rewriter.getI1Type(), three = rewriter.getIntegerType(3),
789 five = rewriter.getIntegerType(5),
790 width = rewriter.getIntegerType(
791 mulf.getType().getIntOrFloatBitWidth());
793 getState<ComponentLoweringState>()
794 .getNewLibraryOpInstance<calyx::MulFOpIEEE754>(
796 {one, one, one, one, width, width, three, width, five, one});
797 return buildLibraryBinaryPipeOp<calyx::MulFOpIEEE754>(rewriter, mulf, mulFOp,
801 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
803 Location loc = cmpf.getLoc();
804 IntegerType one = rewriter.getI1Type(), five = rewriter.getIntegerType(5),
805 width = rewriter.getIntegerType(
806 cmpf.getLhs().getType().getIntOrFloatBitWidth());
807 auto calyxCmpFOp = getState<ComponentLoweringState>()
808 .getNewLibraryOpInstance<calyx::CompareFOpIEEE754>(
810 {one, one, one, width, width, one, one, one, one,
814 rewriter.setInsertionPointToStart(getComponent().
getBodyBlock());
817 using CombLogic = PredicateInfo::CombLogic;
818 using Port = PredicateInfo::InputPorts::Port;
820 if (info.logic == CombLogic::None) {
821 if (cmpf.getPredicate() == CmpFPredicate::AlwaysTrue) {
822 cmpf.getResult().replaceAllUsesWith(c1);
826 if (cmpf.getPredicate() == CmpFPredicate::AlwaysFalse) {
827 cmpf.getResult().replaceAllUsesWith(c0);
833 StringRef opName = cmpf.getOperationName().split(
".").second;
836 getState<ComponentLoweringState>().getUniqueName(opName));
839 auto group = createGroupForOp<calyx::GroupOp>(rewriter, cmpf);
840 OpBuilder builder(group->getRegion(0));
841 getState<ComponentLoweringState>().addBlockScheduleable(cmpf->getBlock(),
844 rewriter.setInsertionPointToEnd(group.getBodyBlock());
845 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getLeft(), cmpf.getLhs());
846 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getRight(), cmpf.getRhs());
848 bool signalingFlag =
false;
849 switch (cmpf.getPredicate()) {
850 case CmpFPredicate::UGT:
851 case CmpFPredicate::UGE:
852 case CmpFPredicate::ULT:
853 case CmpFPredicate::ULE:
854 case CmpFPredicate::OGT:
855 case CmpFPredicate::OGE:
856 case CmpFPredicate::OLT:
857 case CmpFPredicate::OLE:
858 signalingFlag =
true;
860 case CmpFPredicate::UEQ:
861 case CmpFPredicate::UNE:
862 case CmpFPredicate::OEQ:
863 case CmpFPredicate::ONE:
864 case CmpFPredicate::UNO:
865 case CmpFPredicate::ORD:
866 case CmpFPredicate::AlwaysTrue:
867 case CmpFPredicate::AlwaysFalse:
868 signalingFlag =
false;
874 rewriter.create<calyx::AssignOp>(loc, calyxCmpFOp.getSignaling(),
875 signalingFlag ? c1 : c0);
878 SmallVector<calyx::RegisterOp> inputRegs;
879 for (
const auto &input : info.inputPorts) {
881 switch (input.port) {
883 signal = calyxCmpFOp.getEq();
887 signal = calyxCmpFOp.getGt();
891 signal = calyxCmpFOp.getLt();
894 case Port::Unordered: {
895 signal = calyxCmpFOp.getUnordered();
899 std::string nameSuffix =
900 (input.port == PredicateInfo::InputPorts::Port::Unordered)
903 auto signalReg = createSignalRegister(rewriter, signal, input.invert,
904 nameSuffix, calyxCmpFOp, group);
905 inputRegs.push_back(signalReg);
909 Value outputValue, doneValue;
910 switch (info.logic) {
911 case CombLogic::None: {
913 outputValue = inputRegs[0].getOut();
914 doneValue = inputRegs[0].getOut();
917 case CombLogic::And: {
918 auto outputLibOp = getState<ComponentLoweringState>()
919 .getNewLibraryOpInstance<calyx::AndLibOp>(
920 rewriter, loc, {one, one, one});
921 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
922 inputRegs[0].getOut());
923 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
924 inputRegs[1].getOut());
926 outputValue = outputLibOp.getOut();
929 case CombLogic::Or: {
930 auto outputLibOp = getState<ComponentLoweringState>()
931 .getNewLibraryOpInstance<calyx::OrLibOp>(
932 rewriter, loc, {one, one, one});
933 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getLeft(),
934 inputRegs[0].getOut());
935 rewriter.create<calyx::AssignOp>(loc, outputLibOp.getRight(),
936 inputRegs[1].getOut());
938 outputValue = outputLibOp.getOut();
943 if (info.logic != CombLogic::None) {
944 auto doneLibOp = getState<ComponentLoweringState>()
945 .getNewLibraryOpInstance<calyx::AndLibOp>(
946 rewriter, loc, {one, one, one});
947 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getLeft(),
948 inputRegs[0].getDone());
949 rewriter.create<calyx::AssignOp>(loc, doneLibOp.getRight(),
950 inputRegs[1].getDone());
951 doneValue = doneLibOp.getOut();
955 rewriter.create<calyx::AssignOp>(loc,
reg.getIn(), outputValue);
956 rewriter.create<calyx::AssignOp>(loc,
reg.getWriteEn(), doneValue);
959 rewriter.create<calyx::AssignOp>(
960 loc, calyxCmpFOp.getGo(), c1,
962 rewriter.create<calyx::GroupDoneOp>(loc,
reg.getDone());
964 cmpf.getResult().replaceAllUsesWith(
reg.getOut());
967 getState<ComponentLoweringState>().registerEvaluatingGroup(outputValue,
969 getState<ComponentLoweringState>().registerEvaluatingGroup(doneValue, group);
970 getState<ComponentLoweringState>().registerEvaluatingGroup(
971 calyxCmpFOp.getLeft(), group);
972 getState<ComponentLoweringState>().registerEvaluatingGroup(
973 calyxCmpFOp.getRight(), group);
978 template <
typename TAllocOp>
980 PatternRewriter &rewriter, TAllocOp allocOp) {
981 rewriter.setInsertionPointToStart(
983 MemRefType memtype = allocOp.getType();
984 SmallVector<int64_t> addrSizes;
985 SmallVector<int64_t> sizes;
986 for (int64_t dim : memtype.getShape()) {
987 sizes.push_back(dim);
992 if (sizes.empty() && addrSizes.empty()) {
994 addrSizes.push_back(1);
996 auto memoryOp = rewriter.create<calyx::SeqMemoryOp>(
998 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1002 memoryOp->setAttr(
"external",
1007 unsigned elmTyBitWidth = memtype.getElementTypeBitWidth();
1008 assert(elmTyBitWidth <= 64 &&
"element bitwidth should not exceed 64");
1009 bool isFloat = !memtype.getElementType().isInteger();
1011 auto shape = allocOp.getType().getShape();
1013 std::reduce(shape.begin(), shape.end(), 1, std::multiplies<int>());
1020 if (!(shape.size() <= 1 || totalSize <= 1)) {
1021 allocOp.emitError(
"input memory dimension must be empty or one.");
1025 std::vector<uint64_t> flattenedVals(totalSize, 0);
1026 if (isa<memref::GetGlobalOp>(allocOp)) {
1027 auto getGlobalOp = cast<memref::GetGlobalOp>(allocOp);
1028 auto *symbolTableOp =
1029 getGlobalOp->template getParentWithTrait<mlir::OpTrait::SymbolTable>();
1030 auto globalOp = dyn_cast_or_null<memref::GlobalOp>(
1031 SymbolTable::lookupSymbolIn(symbolTableOp, getGlobalOp.getNameAttr()));
1033 auto cstAttr = llvm::dyn_cast_or_null<DenseElementsAttr>(
1034 globalOp.getConstantInitValue());
1036 for (
auto attr : cstAttr.template getValues<Attribute>()) {
1037 assert((isa<mlir::FloatAttr, mlir::IntegerAttr>(attr)) &&
1038 "memory attributes must be float or int");
1039 if (
auto fltAttr = dyn_cast<mlir::FloatAttr>(attr)) {
1040 flattenedVals[sizeCount++] =
1041 bit_cast<uint64_t>(fltAttr.getValueAsDouble());
1043 auto intAttr = dyn_cast<mlir::IntegerAttr>(attr);
1044 APInt value = intAttr.getValue();
1045 flattenedVals[sizeCount++] = *value.getRawData();
1049 rewriter.eraseOp(globalOp);
1052 llvm::json::Array result;
1053 result.reserve(std::max(
static_cast<int>(shape.size()), 1));
1055 Type elemType = memtype.getElementType();
1057 !elemType.isSignlessInteger() && !elemType.isUnsignedInteger();
1058 for (uint64_t bitValue : flattenedVals) {
1059 llvm::json::Value value = 0;
1063 value = bit_cast<double>(bitValue);
1065 APInt apInt(elmTyBitWidth, bitValue, isSigned,
1070 value =
static_cast<int64_t
>(apInt.getSExtValue());
1072 value = apInt.getZExtValue();
1074 result.push_back(std::move(value));
1077 componentState.
setDataField(memoryOp.getName(), result);
1078 std::string numType =
1079 memtype.getElementType().isInteger() ?
"bitnum" :
"ieee754_float";
1080 componentState.
setFormat(memoryOp.getName(), numType, isSigned,
1086 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1087 memref::AllocOp allocOp)
const {
1088 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1091 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1092 memref::AllocaOp allocOp)
const {
1093 return buildAllocOp(getState<ComponentLoweringState>(), rewriter, allocOp);
1096 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1097 memref::GetGlobalOp getGlobalOp)
const {
1098 return buildAllocOp(getState<ComponentLoweringState>(), rewriter,
1102 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1103 scf::YieldOp yieldOp)
const {
1104 if (yieldOp.getOperands().empty()) {
1106 auto forOp = dyn_cast<scf::ForOp>(yieldOp->getParentOp());
1107 assert(forOp &&
"Empty yieldOps should only be located within ForOps");
1112 getState<ComponentLoweringState>().getForLoopIterReg(forOpInterface, 0);
1114 Type regWidth = inductionReg.getOut().getType();
1116 SmallVector<Type> types(3, regWidth);
1117 auto addOp = getState<ComponentLoweringState>()
1118 .getNewLibraryOpInstance<calyx::AddLibOp>(
1119 rewriter, forOp.getLoc(), types);
1121 auto directions = addOp.portDirections();
1123 SmallVector<Value, 2> opInputPorts;
1125 for (
auto dir : enumerate(directions)) {
1126 switch (dir.value()) {
1128 opInputPorts.push_back(addOp.getResult(dir.index()));
1132 opOutputPort = addOp.getResult(dir.index());
1139 calyx::ComponentOp componentOp =
1140 getState<ComponentLoweringState>().getComponentOp();
1141 SmallVector<StringRef, 4> groupIdentifier = {
1142 "incr", getState<ComponentLoweringState>().getUniqueName(forOp),
1143 "induction",
"var"};
1144 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1145 rewriter, componentOp, forOp.getLoc(),
1146 llvm::join(groupIdentifier,
"_"));
1147 rewriter.setInsertionPointToEnd(groupOp.getBodyBlock());
1150 Value leftOp = opInputPorts.front();
1151 rewriter.create<calyx::AssignOp>(forOp.getLoc(), leftOp,
1152 inductionReg.getOut());
1154 Value rightOp = opInputPorts.back();
1155 rewriter.create<calyx::AssignOp>(
1156 forOp.getLoc(), rightOp,
1158 regWidth.getIntOrFloatBitWidth(),
1159 forOp.getConstantStep().value().getSExtValue()));
1162 inductionReg, opOutputPort);
1164 getState<ComponentLoweringState>().setForLoopLatchGroup(forOpInterface,
1166 getState<ComponentLoweringState>().registerEvaluatingGroup(opOutputPort,
1171 if (dyn_cast<scf::ForOp>(yieldOp->getParentOp())) {
1172 return yieldOp.getOperation()->emitError()
1173 <<
"Currently do not support non-empty yield operations inside for "
1174 "loops. Run --scf-for-to-while before running --scf-to-calyx.";
1177 if (
auto whileOp = dyn_cast<scf::WhileOp>(yieldOp->getParentOp())) {
1181 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1182 rewriter, whileOpInterface,
1183 getState<ComponentLoweringState>().getComponentOp(),
1184 getState<ComponentLoweringState>().getUniqueName(whileOp) +
1186 yieldOp->getOpOperands());
1187 getState<ComponentLoweringState>().setWhileLoopLatchGroup(whileOpInterface,
1192 if (
auto ifOp = dyn_cast<scf::IfOp>(yieldOp->getParentOp())) {
1193 auto resultRegs = getState<ComponentLoweringState>().getResultRegs(ifOp);
1195 if (yieldOp->getParentRegion() == &ifOp.getThenRegion()) {
1196 auto thenGroup = getState<ComponentLoweringState>().getThenGroup(ifOp);
1197 for (
auto op : enumerate(yieldOp.getOperands())) {
1199 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1201 rewriter, thenGroup,
1202 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1204 getState<ComponentLoweringState>().registerEvaluatingGroup(
1205 ifOp.getResult(op.index()), thenGroup);
1209 if (!ifOp.getElseRegion().empty() &&
1210 (yieldOp->getParentRegion() == &ifOp.getElseRegion())) {
1211 auto elseGroup = getState<ComponentLoweringState>().getElseGroup(ifOp);
1212 for (
auto op : enumerate(yieldOp.getOperands())) {
1214 getState<ComponentLoweringState>().getResultRegs(ifOp, op.index());
1216 rewriter, elseGroup,
1217 getState<ComponentLoweringState>().getComponentOp(), resultReg,
1219 getState<ComponentLoweringState>().registerEvaluatingGroup(
1220 ifOp.getResult(op.index()), elseGroup);
1227 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1228 BranchOpInterface brOp)
const {
1233 Block *srcBlock = brOp->getBlock();
1234 for (
auto succBlock : enumerate(brOp->getSuccessors())) {
1235 auto succOperands = brOp.getSuccessorOperands(succBlock.index());
1236 if (succOperands.empty())
1239 std::string groupName =
loweringState().blockName(srcBlock) +
"_to_" +
1241 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
1242 brOp.getLoc(), groupName);
1244 auto dstBlockArgRegs =
1245 getState<ComponentLoweringState>().getBlockArgRegs(succBlock.value());
1247 for (
auto arg : enumerate(succOperands.getForwardedOperands())) {
1248 auto reg = dstBlockArgRegs[arg.index()];
1251 getState<ComponentLoweringState>().getComponentOp(),
reg,
1256 getState<ComponentLoweringState>().addBlockArgGroup(
1257 srcBlock, succBlock.value(), groupOp);
1264 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1265 ReturnOp retOp)
const {
1266 if (retOp.getNumOperands() == 0)
1269 std::string groupName =
1270 getState<ComponentLoweringState>().getUniqueName(
"ret_assign");
1271 auto groupOp = calyx::createGroup<calyx::GroupOp>(rewriter, getComponent(),
1272 retOp.getLoc(), groupName);
1273 for (
auto op : enumerate(retOp.getOperands())) {
1274 auto reg = getState<ComponentLoweringState>().getReturnReg(op.index());
1276 rewriter, groupOp, getState<ComponentLoweringState>().getComponentOp(),
1280 getState<ComponentLoweringState>().addBlockScheduleable(retOp->getBlock(),
1285 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1286 arith::ConstantOp constOp)
const {
1287 if (isa<IntegerType>(constOp.getType())) {
1293 hwConstOp->moveAfter(getComponent().getBodyBlock(),
1294 getComponent().getBodyBlock()->begin());
1296 std::string name = getState<ComponentLoweringState>().getUniqueName(
"cst");
1297 auto floatAttr = cast<FloatAttr>(constOp.getValueAttr());
1299 rewriter.getIntegerType(floatAttr.getType().getIntOrFloatBitWidth());
1300 auto calyxConstOp = rewriter.create<calyx::ConstantOp>(
1301 constOp.getLoc(), name, floatAttr, intType);
1302 calyxConstOp->moveAfter(getComponent().getBodyBlock(),
1303 getComponent().getBodyBlock()->begin());
1304 rewriter.replaceAllUsesWith(constOp, calyxConstOp.getOut());
1310 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1312 return buildLibraryOp<calyx::CombGroupOp, calyx::AddLibOp>(rewriter, op);
1314 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1316 return buildLibraryOp<calyx::CombGroupOp, calyx::SubLibOp>(rewriter, op);
1318 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1320 return buildLibraryOp<calyx::CombGroupOp, calyx::RshLibOp>(rewriter, op);
1322 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1324 return buildLibraryOp<calyx::CombGroupOp, calyx::SrshLibOp>(rewriter, op);
1326 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1328 return buildLibraryOp<calyx::CombGroupOp, calyx::LshLibOp>(rewriter, op);
1330 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1332 return buildLibraryOp<calyx::CombGroupOp, calyx::AndLibOp>(rewriter, op);
1334 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1336 return buildLibraryOp<calyx::CombGroupOp, calyx::OrLibOp>(rewriter, op);
1338 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1340 return buildLibraryOp<calyx::CombGroupOp, calyx::XorLibOp>(rewriter, op);
1342 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1343 SelectOp op)
const {
1344 return buildLibraryOp<calyx::CombGroupOp, calyx::MuxLibOp>(rewriter, op);
1347 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1349 switch (op.getPredicate()) {
1350 case CmpIPredicate::eq:
1351 return buildLibraryOp<calyx::CombGroupOp, calyx::EqLibOp>(rewriter, op);
1352 case CmpIPredicate::ne:
1353 return buildLibraryOp<calyx::CombGroupOp, calyx::NeqLibOp>(rewriter, op);
1354 case CmpIPredicate::uge:
1355 return buildLibraryOp<calyx::CombGroupOp, calyx::GeLibOp>(rewriter, op);
1356 case CmpIPredicate::ult:
1357 return buildLibraryOp<calyx::CombGroupOp, calyx::LtLibOp>(rewriter, op);
1358 case CmpIPredicate::ugt:
1359 return buildLibraryOp<calyx::CombGroupOp, calyx::GtLibOp>(rewriter, op);
1360 case CmpIPredicate::ule:
1361 return buildLibraryOp<calyx::CombGroupOp, calyx::LeLibOp>(rewriter, op);
1362 case CmpIPredicate::sge:
1363 return buildLibraryOp<calyx::CombGroupOp, calyx::SgeLibOp>(rewriter, op);
1364 case CmpIPredicate::slt:
1365 return buildLibraryOp<calyx::CombGroupOp, calyx::SltLibOp>(rewriter, op);
1366 case CmpIPredicate::sgt:
1367 return buildLibraryOp<calyx::CombGroupOp, calyx::SgtLibOp>(rewriter, op);
1368 case CmpIPredicate::sle:
1369 return buildLibraryOp<calyx::CombGroupOp, calyx::SleLibOp>(rewriter, op);
1371 llvm_unreachable(
"unsupported comparison predicate");
1373 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1374 TruncIOp op)
const {
1375 return buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1376 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1378 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1380 return buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1381 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1384 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1386 return buildLibraryOp<calyx::CombGroupOp, calyx::ExtSILibOp>(
1387 rewriter, op, {op.getOperand().getType()}, {op.getType()});
1390 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1391 IndexCastOp op)
const {
1394 unsigned targetBits = targetType.getIntOrFloatBitWidth();
1395 unsigned sourceBits = sourceType.getIntOrFloatBitWidth();
1396 LogicalResult res = success();
1398 if (targetBits == sourceBits) {
1401 op.getResult().replaceAllUsesWith(op.getOperand());
1404 if (sourceBits > targetBits)
1405 res = buildLibraryOp<calyx::CombGroupOp, calyx::SliceLibOp>(
1406 rewriter, op, {sourceType}, {targetType});
1408 res = buildLibraryOp<calyx::CombGroupOp, calyx::PadLibOp>(
1409 rewriter, op, {sourceType}, {targetType});
1411 rewriter.eraseOp(op);
1415 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1416 scf::WhileOp whileOp)
const {
1420 getState<ComponentLoweringState>().addBlockScheduleable(
1425 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1426 scf::ForOp forOp)
const {
1432 std::optional<uint64_t> bound = scfForOp.
getBound();
1433 if (!bound.has_value()) {
1435 <<
"Loop bound not statically known. Should "
1436 "transform into while loop using `--scf-for-to-while` before "
1437 "running --lower-scf-to-calyx.";
1439 getState<ComponentLoweringState>().addBlockScheduleable(
1447 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1448 scf::IfOp ifOp)
const {
1449 getState<ComponentLoweringState>().addBlockScheduleable(
1454 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1455 scf::ReduceOp reduceOp)
const {
1462 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1463 scf::ParallelOp parOp)
const {
1464 getState<ComponentLoweringState>().addBlockScheduleable(
1469 LogicalResult BuildOpGroups::buildOp(PatternRewriter &rewriter,
1470 CallOp callOp)
const {
1472 calyx::InstanceOp instanceOp =
1473 getState<ComponentLoweringState>().getInstance(instanceName);
1474 SmallVector<Value, 4> outputPorts;
1475 auto portInfos = instanceOp.getReferencedComponent().getPortInfo();
1476 for (
auto [idx, portInfo] : enumerate(portInfos)) {
1478 outputPorts.push_back(instanceOp.getResult(idx));
1482 for (
auto [idx, result] : llvm::enumerate(callOp.getResults()))
1483 rewriter.replaceAllUsesWith(result, outputPorts[idx]);
1487 getState<ComponentLoweringState>().addBlockScheduleable(
1501 using OpRewritePattern::OpRewritePattern;
1504 PatternRewriter &rewriter)
const override {
1506 TypeRange yieldTypes = execOp.getResultTypes();
1510 rewriter.setInsertionPointAfter(execOp);
1511 auto *sinkBlock = rewriter.splitBlock(
1513 execOp.getOperation()->getIterator()->getNextNode()->getIterator());
1514 sinkBlock->addArguments(
1516 SmallVector<Location, 4>(yieldTypes.size(), rewriter.getUnknownLoc()));
1517 for (
auto res : enumerate(execOp.getResults()))
1518 res.value().replaceAllUsesWith(sinkBlock->getArgument(res.index()));
1522 make_early_inc_range(execOp.getRegion().getOps<scf::YieldOp>())) {
1523 rewriter.setInsertionPointAfter(yieldOp);
1524 rewriter.replaceOpWithNewOp<BranchOp>(yieldOp, sinkBlock,
1525 yieldOp.getOperands());
1529 auto *preBlock = execOp->getBlock();
1530 auto *execOpEntryBlock = &execOp.getRegion().front();
1531 auto *postBlock = execOp->getBlock()->splitBlock(execOp);
1532 rewriter.inlineRegionBefore(execOp.getRegion(), postBlock);
1533 rewriter.mergeBlocks(postBlock, preBlock);
1534 rewriter.eraseOp(execOp);
1537 rewriter.mergeBlocks(execOpEntryBlock, preBlock);
1545 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1549 PatternRewriter &rewriter)
const override {
1552 DenseMap<Value, unsigned> funcOpArgRewrites;
1556 DenseMap<unsigned, unsigned> funcOpResultMapping;
1564 DenseMap<Value, std::pair<unsigned, unsigned>> extMemoryCompPortIndices;
1568 SmallVector<calyx::PortInfo> inPorts, outPorts;
1569 FunctionType funcType = funcOp.getFunctionType();
1570 for (
auto arg : enumerate(funcOp.getArguments())) {
1571 if (!isa<MemRefType>(arg.value().getType())) {
1574 if (
auto portNameAttr = funcOp.getArgAttrOfType<StringAttr>(
1576 inName = portNameAttr.str();
1578 inName =
"in" + std::to_string(arg.index());
1579 funcOpArgRewrites[arg.value()] = inPorts.size();
1581 rewriter.getStringAttr(inName),
1587 for (
auto res : enumerate(funcType.getResults())) {
1588 std::string resName;
1589 if (
auto portNameAttr = funcOp.getResultAttrOfType<StringAttr>(
1591 resName = portNameAttr.str();
1593 resName =
"out" + std::to_string(res.index());
1594 funcOpResultMapping[res.index()] = outPorts.size();
1597 rewriter.getStringAttr(resName),
1604 auto ports = inPorts;
1605 llvm::append_range(ports, outPorts);
1609 auto compOp = rewriter.create<calyx::ComponentOp>(
1610 funcOp.getLoc(), rewriter.getStringAttr(funcOp.getSymName()), ports);
1612 std::string funcName =
"func_" + funcOp.getSymName().str();
1613 rewriter.modifyOpInPlace(funcOp, [&]() { funcOp.setSymName(funcName); });
1617 if (compOp.getName() ==
loweringState().getTopLevelFunction())
1618 compOp->setAttr(
"toplevel", rewriter.getUnitAttr());
1621 functionMapping[funcOp] = compOp;
1625 unsigned extMemCounter = 0;
1626 for (
auto arg : enumerate(funcOp.getArguments())) {
1627 if (isa<MemRefType>(arg.value().getType())) {
1628 std::string memName =
1629 llvm::join_items(
"_",
"arg_mem", std::to_string(extMemCounter++));
1631 rewriter.setInsertionPointToStart(compOp.getBodyBlock());
1632 MemRefType memtype = cast<MemRefType>(arg.value().getType());
1633 SmallVector<int64_t> addrSizes;
1634 SmallVector<int64_t> sizes;
1635 for (int64_t dim : memtype.getShape()) {
1636 sizes.push_back(dim);
1639 if (sizes.empty() && addrSizes.empty()) {
1641 addrSizes.push_back(1);
1643 auto memOp = rewriter.create<calyx::SeqMemoryOp>(
1644 funcOp.getLoc(), memName,
1645 memtype.getElementType().getIntOrFloatBitWidth(), sizes, addrSizes);
1648 compState->registerMemoryInterface(arg.value(),
1654 for (
auto &mapping : funcOpArgRewrites)
1655 mapping.getFirst().replaceAllUsesWith(
1656 compOp.getArgument(mapping.getSecond()));
1667 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1671 PatternRewriter &rewriter)
const override {
1672 LogicalResult res = success();
1673 funcOp.walk([&](Operation *op) {
1675 if (!isa<scf::WhileOp>(op))
1676 return WalkResult::advance();
1678 auto scfWhileOp = cast<scf::WhileOp>(op);
1681 getState<ComponentLoweringState>().setUniqueName(whileOp.
getOperation(),
1691 enumerate(scfWhileOp.getBefore().front().getArguments())) {
1692 auto condOp = scfWhileOp.getConditionOp().getArgs()[barg.index()];
1693 if (barg.value() != condOp) {
1697 <<
"do-while loops not supported; expected iter-args to "
1698 "remain untransformed in the 'before' region of the "
1700 return WalkResult::interrupt();
1709 for (
auto arg : enumerate(whileOp.
getBodyArgs())) {
1710 std::string name = getState<ComponentLoweringState>()
1713 "_arg" + std::to_string(arg.index());
1716 arg.value().getType().getIntOrFloatBitWidth(), name);
1717 getState<ComponentLoweringState>().addWhileLoopIterReg(whileOp,
reg,
1719 arg.value().replaceAllUsesWith(
reg.getOut());
1723 ->getArgument(arg.index())
1724 .replaceAllUsesWith(
reg.getOut());
1728 SmallVector<calyx::GroupOp> initGroups;
1729 auto numOperands = whileOp.
getOperation()->getNumOperands();
1730 for (
size_t i = 0; i < numOperands; ++i) {
1732 getState<ComponentLoweringState>().buildWhileLoopIterArgAssignments(
1734 getState<ComponentLoweringState>().getComponentOp(),
1735 getState<ComponentLoweringState>().getUniqueName(
1737 "_init_" + std::to_string(i),
1739 initGroups.push_back(initGroupOp);
1742 getState<ComponentLoweringState>().setWhileLoopInitGroups(whileOp,
1745 return WalkResult::advance();
1755 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1759 PatternRewriter &rewriter)
const override {
1760 LogicalResult res = success();
1761 funcOp.walk([&](Operation *op) {
1763 if (!isa<scf::ForOp>(op))
1764 return WalkResult::advance();
1766 auto scfForOp = cast<scf::ForOp>(op);
1769 getState<ComponentLoweringState>().setUniqueName(forOp.
getOperation(),
1774 auto inductionVar = forOp.
getOperation().getInductionVar();
1775 SmallVector<std::string, 3> inductionVarIdentifiers = {
1776 getState<ComponentLoweringState>()
1779 "induction",
"var"};
1780 std::string name = llvm::join(inductionVarIdentifiers,
"_");
1783 inductionVar.getType().getIntOrFloatBitWidth(), name);
1784 getState<ComponentLoweringState>().addForLoopIterReg(forOp,
reg, 0);
1785 inductionVar.replaceAllUsesWith(
reg.getOut());
1788 calyx::ComponentOp componentOp =
1789 getState<ComponentLoweringState>().getComponentOp();
1790 SmallVector<calyx::GroupOp> initGroups;
1791 SmallVector<std::string, 4> groupIdentifiers = {
1793 getState<ComponentLoweringState>()
1796 "induction",
"var"};
1797 std::string groupName = llvm::join(groupIdentifiers,
"_");
1798 auto groupOp = calyx::createGroup<calyx::GroupOp>(
1799 rewriter, componentOp, forOp.
getLoc(), groupName);
1802 initGroups.push_back(groupOp);
1803 getState<ComponentLoweringState>().setForLoopInitGroups(forOp,
1806 return WalkResult::advance();
1813 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1817 PatternRewriter &rewriter)
const override {
1818 LogicalResult res = success();
1819 funcOp.walk([&](Operation *op) {
1820 if (!isa<scf::IfOp>(op))
1821 return WalkResult::advance();
1823 auto scfIfOp = cast<scf::IfOp>(op);
1825 calyx::ComponentOp componentOp =
1826 getState<ComponentLoweringState>().getComponentOp();
1828 std::string thenGroupName =
1829 getState<ComponentLoweringState>().getUniqueName(
"then_br");
1830 auto thenGroupOp = calyx::createGroup<calyx::GroupOp>(
1831 rewriter, componentOp, scfIfOp.getLoc(), thenGroupName);
1832 getState<ComponentLoweringState>().setThenGroup(scfIfOp, thenGroupOp);
1834 if (!scfIfOp.getElseRegion().empty()) {
1835 std::string elseGroupName =
1836 getState<ComponentLoweringState>().getUniqueName(
"else_br");
1837 auto elseGroupOp = calyx::createGroup<calyx::GroupOp>(
1838 rewriter, componentOp, scfIfOp.getLoc(), elseGroupName);
1839 getState<ComponentLoweringState>().setElseGroup(scfIfOp, elseGroupOp);
1842 for (
auto ifOpRes : scfIfOp.getResults()) {
1844 scfIfOp.getLoc(), rewriter, getComponent(),
1845 ifOpRes.getType().getIntOrFloatBitWidth(),
1846 getState<ComponentLoweringState>().getUniqueName(
"if_res"));
1847 getState<ComponentLoweringState>().setResultRegs(
1848 scfIfOp,
reg, ifOpRes.getResultNumber());
1851 return WalkResult::advance();
1858 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1862 PatternRewriter &rewriter)
const override {
1863 WalkResult walkResult = funcOp.walk([&](scf::ParallelOp scfParOp) {
1864 if (!scfParOp.getResults().empty()) {
1866 "Reduce operations in scf.parallel is not supported yet");
1867 return WalkResult::interrupt();
1870 if (failed(partialEval(rewriter, scfParOp)))
1871 return WalkResult::interrupt();
1873 return WalkResult::advance();
1876 return walkResult.wasInterrupted() ? failure() : success();
1883 scf::ParallelOp scfParOp)
const {
1884 assert(scfParOp.getLoopSteps() &&
"Parallel loop must have steps");
1885 auto *body = scfParOp.getBody();
1886 auto parOpIVs = scfParOp.getInductionVars();
1887 auto steps = scfParOp.getStep();
1888 auto lowerBounds = scfParOp.getLowerBound();
1889 auto upperBounds = scfParOp.getUpperBound();
1890 rewriter.setInsertionPointAfter(scfParOp);
1891 scf::ParallelOp newParOp = scfParOp.cloneWithoutRegions();
1892 auto loc = newParOp.getLoc();
1893 rewriter.insert(newParOp);
1894 OpBuilder insideBuilder(newParOp);
1895 Block *currBlock =
nullptr;
1896 auto ®ion = newParOp.getRegion();
1897 IRMapping operandMap;
1900 SmallVector<int64_t> lbVals, ubVals, stepVals;
1901 for (
auto lb : lowerBounds) {
1902 auto lbOp = lb.getDefiningOp<arith::ConstantIndexOp>();
1904 "Lower bound must be a statically computable constant index");
1905 lbVals.push_back(lbOp.value());
1907 for (
auto ub : upperBounds) {
1908 auto ubOp = ub.getDefiningOp<arith::ConstantIndexOp>();
1910 "Upper bound must be a statically computable constant index");
1911 ubVals.push_back(ubOp.value());
1913 for (
auto step : steps) {
1914 auto stepOp = step.getDefiningOp<arith::ConstantIndexOp>();
1915 assert(stepOp &&
"Step must be a statically computable constant index");
1916 stepVals.push_back(stepOp.value());
1920 SmallVector<int64_t> indices = lbVals;
1924 currBlock = ®ion.emplaceBlock();
1925 insideBuilder.setInsertionPointToEnd(currBlock);
1928 for (
unsigned i = 0; i < indices.size(); ++i) {
1930 insideBuilder.create<arith::ConstantIndexOp>(loc, indices[i]);
1931 operandMap.map(parOpIVs[i], ivConstant);
1934 for (
auto it = body->begin(); it != std::prev(body->end()); ++it)
1935 insideBuilder.clone(*it, operandMap);
1939 for (
int dim = indices.size() - 1; dim >= 0; --dim) {
1940 indices[dim] += stepVals[dim];
1941 if (indices[dim] < ubVals[dim])
1943 indices[dim] = lbVals[dim];
1952 rewriter.replaceOp(scfParOp, newParOp);
1963 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
1967 PatternRewriter &rewriter)
const override {
1968 auto *entryBlock = &funcOp.getBlocks().front();
1969 rewriter.setInsertionPointToStart(
1971 auto topLevelSeqOp = rewriter.create<calyx::SeqOp>(funcOp.getLoc());
1972 DenseSet<Block *> path;
1973 return buildCFGControl(path, rewriter, topLevelSeqOp.getBodyBlock(),
1974 nullptr, entryBlock);
1981 const DenseSet<Block *> &path,
1982 mlir::Block *parentCtrlBlock,
1983 mlir::Block *block)
const {
1984 auto compBlockScheduleables =
1985 getState<ComponentLoweringState>().getBlockScheduleables(block);
1986 auto loc = block->front().getLoc();
1988 if (compBlockScheduleables.size() > 1 &&
1989 !isa<scf::ParallelOp>(block->getParentOp())) {
1990 auto seqOp = rewriter.create<calyx::SeqOp>(loc);
1991 parentCtrlBlock = seqOp.getBodyBlock();
1994 for (
auto &group : compBlockScheduleables) {
1995 rewriter.setInsertionPointToEnd(parentCtrlBlock);
1996 if (
auto groupPtr = std::get_if<calyx::GroupOp>(&group); groupPtr) {
1997 rewriter.create<calyx::EnableOp>(groupPtr->getLoc(),
1998 groupPtr->getSymName());
1999 }
else if (
auto whileSchedPtr = std::get_if<WhileScheduleable>(&group);
2001 auto &whileOp = whileSchedPtr->whileOp;
2003 auto whileCtrlOp = buildWhileCtrlOp(
2005 getState<ComponentLoweringState>().getWhileLoopInitGroups(whileOp),
2007 rewriter.setInsertionPointToEnd(whileCtrlOp.getBodyBlock());
2009 rewriter.create<calyx::SeqOp>(whileOp.getOperation()->getLoc());
2010 auto *whileBodyOpBlock = whileBodyOp.getBodyBlock();
2014 if (LogicalResult result =
2015 buildCFGControl(path, rewriter, whileBodyOpBlock, block,
2016 whileOp.getBodyBlock());
2021 rewriter.setInsertionPointToEnd(whileBodyOpBlock);
2022 calyx::GroupOp whileLatchGroup =
2023 getState<ComponentLoweringState>().getWhileLoopLatchGroup(whileOp);
2024 rewriter.create<calyx::EnableOp>(whileLatchGroup.getLoc(),
2025 whileLatchGroup.getName());
2026 }
else if (
auto *parSchedPtr = std::get_if<ParScheduleable>(&group)) {
2027 auto parOp = parSchedPtr->parOp;
2028 auto calyxParOp = rewriter.create<calyx::ParOp>(parOp.getLoc());
2029 for (
auto &innerBlock : parOp.getRegion().getBlocks()) {
2030 rewriter.setInsertionPointToEnd(calyxParOp.getBodyBlock());
2031 auto seqOp = rewriter.create<calyx::SeqOp>(parOp.getLoc());
2032 rewriter.setInsertionPointToEnd(seqOp.getBodyBlock());
2033 if (LogicalResult res = scheduleBasicBlock(
2034 rewriter, path, seqOp.getBodyBlock(), &innerBlock);
2038 }
else if (
auto *forSchedPtr = std::get_if<ForScheduleable>(&group);
2040 auto forOp = forSchedPtr->forOp;
2042 auto forCtrlOp = buildForCtrlOp(
2044 getState<ComponentLoweringState>().getForLoopInitGroups(forOp),
2045 forSchedPtr->bound, rewriter);
2046 rewriter.setInsertionPointToEnd(forCtrlOp.getBodyBlock());
2048 rewriter.create<calyx::SeqOp>(forOp.getOperation()->getLoc());
2049 auto *forBodyOpBlock = forBodyOp.getBodyBlock();
2052 if (LogicalResult res = buildCFGControl(path, rewriter, forBodyOpBlock,
2053 block, forOp.getBodyBlock());
2058 rewriter.setInsertionPointToEnd(forBodyOpBlock);
2059 calyx::GroupOp forLatchGroup =
2060 getState<ComponentLoweringState>().getForLoopLatchGroup(forOp);
2061 rewriter.create<calyx::EnableOp>(forLatchGroup.getLoc(),
2062 forLatchGroup.getName());
2063 }
else if (
auto *ifSchedPtr = std::get_if<IfScheduleable>(&group);
2065 auto ifOp = ifSchedPtr->ifOp;
2067 Location loc = ifOp->getLoc();
2069 auto cond = ifOp.getCondition();
2070 auto condGroup = getState<ComponentLoweringState>()
2071 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2076 bool initElse = !ifOp.getElseRegion().empty();
2077 auto ifCtrlOp = rewriter.create<calyx::IfOp>(
2078 loc, cond, symbolAttr, initElse);
2080 rewriter.setInsertionPointToEnd(ifCtrlOp.getBodyBlock());
2083 rewriter.create<calyx::SeqOp>(ifOp.getThenRegion().getLoc());
2084 auto *thenSeqOpBlock = thenSeqOp.getBodyBlock();
2086 auto *thenBlock = &ifOp.getThenRegion().front();
2087 LogicalResult res = buildCFGControl(path, rewriter, thenSeqOpBlock,
2092 rewriter.setInsertionPointToEnd(thenSeqOpBlock);
2093 calyx::GroupOp thenGroup =
2094 getState<ComponentLoweringState>().getThenGroup(ifOp);
2095 rewriter.create<calyx::EnableOp>(thenGroup.getLoc(),
2096 thenGroup.getName());
2098 if (!ifOp.getElseRegion().empty()) {
2099 rewriter.setInsertionPointToEnd(ifCtrlOp.getElseBody());
2102 rewriter.create<calyx::SeqOp>(ifOp.getElseRegion().getLoc());
2103 auto *elseSeqOpBlock = elseSeqOp.getBodyBlock();
2105 auto *elseBlock = &ifOp.getElseRegion().front();
2106 res = buildCFGControl(path, rewriter, elseSeqOpBlock,
2111 rewriter.setInsertionPointToEnd(elseSeqOpBlock);
2112 calyx::GroupOp elseGroup =
2113 getState<ComponentLoweringState>().getElseGroup(ifOp);
2114 rewriter.create<calyx::EnableOp>(elseGroup.getLoc(),
2115 elseGroup.getName());
2117 }
else if (
auto *callSchedPtr = std::get_if<CallScheduleable>(&group)) {
2118 auto instanceOp = callSchedPtr->instanceOp;
2119 OpBuilder::InsertionGuard g(rewriter);
2120 auto callBody = rewriter.create<calyx::SeqOp>(instanceOp.getLoc());
2121 rewriter.setInsertionPointToStart(callBody.getBodyBlock());
2122 std::string initGroupName =
"init_" + instanceOp.getSymName().str();
2123 rewriter.create<calyx::EnableOp>(instanceOp.getLoc(), initGroupName);
2125 auto callee = callSchedPtr->callOp.getCallee();
2126 auto *calleeOp = SymbolTable::lookupNearestSymbolFrom(
2127 callSchedPtr->callOp.getOperation()->getParentOp(),
2129 FuncOp calleeFunc = dyn_cast_or_null<FuncOp>(calleeOp);
2131 auto instanceOpComp =
2132 llvm::cast<calyx::ComponentOp>(instanceOp.getReferencedComponent());
2133 auto *instanceOpLoweringState =
2136 SmallVector<Value, 4> instancePorts;
2137 SmallVector<Value, 4> inputPorts;
2138 SmallVector<Attribute, 4> refCells;
2139 for (
auto operandEnum : enumerate(callSchedPtr->callOp.getOperands())) {
2140 auto operand = operandEnum.value();
2141 auto index = operandEnum.index();
2142 if (!isa<MemRefType>(operand.getType())) {
2143 inputPorts.push_back(operand);
2147 auto memOpName = getState<ComponentLoweringState>()
2148 .getMemoryInterface(operand)
2150 auto memOpNameAttr =
2152 Value argI = calleeFunc.getArgument(index);
2153 if (isa<MemRefType>(argI.getType())) {
2154 NamedAttrList namedAttrList;
2155 namedAttrList.append(
2156 rewriter.getStringAttr(
2157 instanceOpLoweringState->getMemoryInterface(argI)
2164 llvm::copy(instanceOp.getResults().take_front(inputPorts.size()),
2165 std::back_inserter(instancePorts));
2167 ArrayAttr refCellsAttr =
2170 rewriter.create<calyx::InvokeOp>(
2171 instanceOp.getLoc(), instanceOp.getSymName(), instancePorts,
2172 inputPorts, refCellsAttr,
ArrayAttr::get(rewriter.getContext(), {}),
2175 llvm_unreachable(
"Unknown scheduleable");
2186 const DenseSet<Block *> &path, Location loc,
2187 Block *from, Block *to,
2188 Block *parentCtrlBlock)
const {
2191 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2192 auto preSeqOp = rewriter.create<calyx::SeqOp>(loc);
2193 rewriter.setInsertionPointToEnd(preSeqOp.getBodyBlock());
2195 getState<ComponentLoweringState>().getBlockArgGroups(from, to))
2196 rewriter.create<calyx::EnableOp>(barg.getLoc(), barg.getSymName());
2198 return buildCFGControl(path, rewriter, parentCtrlBlock, from, to);
2202 PatternRewriter &rewriter,
2203 mlir::Block *parentCtrlBlock,
2204 mlir::Block *preBlock,
2205 mlir::Block *block)
const {
2206 if (path.count(block) != 0)
2207 return preBlock->getTerminator()->emitError()
2208 <<
"CFG backedge detected. Loops must be raised to 'scf.while' or "
2209 "'scf.for' operations.";
2211 rewriter.setInsertionPointToEnd(parentCtrlBlock);
2212 LogicalResult bbSchedResult =
2213 scheduleBasicBlock(rewriter, path, parentCtrlBlock, block);
2214 if (bbSchedResult.failed())
2215 return bbSchedResult;
2218 auto successors = block->getSuccessors();
2219 auto nSuccessors = successors.size();
2220 if (nSuccessors > 0) {
2221 auto brOp = dyn_cast<BranchOpInterface>(block->getTerminator());
2223 if (nSuccessors > 1) {
2227 assert(nSuccessors == 2 &&
2228 "only conditional branches supported for now...");
2230 auto cond = brOp->getOperand(0);
2231 auto condGroup = getState<ComponentLoweringState>()
2232 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2236 auto ifOp = rewriter.create<calyx::IfOp>(
2237 brOp->getLoc(), cond, symbolAttr,
true);
2238 rewriter.setInsertionPointToStart(ifOp.getThenBody());
2239 auto thenSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2240 rewriter.setInsertionPointToStart(ifOp.getElseBody());
2241 auto elseSeqOp = rewriter.create<calyx::SeqOp>(brOp.getLoc());
2243 bool trueBrSchedSuccess =
2244 schedulePath(rewriter, path, brOp.getLoc(), block, successors[0],
2245 thenSeqOp.getBodyBlock())
2247 bool falseBrSchedSuccess =
true;
2248 if (trueBrSchedSuccess) {
2249 falseBrSchedSuccess =
2250 schedulePath(rewriter, path, brOp.getLoc(), block, successors[1],
2251 elseSeqOp.getBodyBlock())
2255 return success(trueBrSchedSuccess && falseBrSchedSuccess);
2258 return schedulePath(rewriter, path, brOp.getLoc(), block,
2259 successors.front(), parentCtrlBlock);
2269 const SmallVector<calyx::GroupOp> &initGroups)
const {
2270 PatternRewriter::InsertionGuard g(rewriter);
2271 auto parOp = rewriter.create<calyx::ParOp>(loc);
2272 rewriter.setInsertionPointToStart(parOp.getBodyBlock());
2273 for (calyx::GroupOp group : initGroups)
2274 rewriter.create<calyx::EnableOp>(group.getLoc(), group.getName());
2278 SmallVector<calyx::GroupOp> initGroups,
2279 PatternRewriter &rewriter)
const {
2280 Location loc = whileOp.
getLoc();
2283 insertParInitGroups(rewriter, loc, initGroups);
2287 auto condGroup = getState<ComponentLoweringState>()
2288 .getEvaluatingGroup<calyx::CombGroupOp>(cond);
2291 return rewriter.create<calyx::WhileOp>(loc, cond, symbolAttr);
2295 SmallVector<calyx::GroupOp>
const &initGroups,
2297 PatternRewriter &rewriter)
const {
2298 Location loc = forOp.
getLoc();
2301 insertParInitGroups(rewriter, loc, initGroups);
2304 return rewriter.create<calyx::RepeatOp>(loc, bound);
2311 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2314 PatternRewriter &)
const override {
2315 funcOp.walk([&](scf::IfOp op) {
2316 for (
auto res : getState<ComponentLoweringState>().getResultRegs(op))
2317 op.getOperation()->getResults()[res.first].replaceAllUsesWith(
2318 res.second.getOut());
2321 funcOp.walk([&](scf::WhileOp op) {
2330 getState<ComponentLoweringState>().getWhileLoopIterRegs(whileOp))
2331 whileOp.
getOperation()->getResults()[res.first].replaceAllUsesWith(
2332 res.second.getOut());
2335 funcOp.walk([&](memref::LoadOp loadOp) {
2341 loadOp.getResult().replaceAllUsesWith(
2342 getState<ComponentLoweringState>()
2343 .getMemoryInterface(loadOp.getMemref())
2354 using FuncOpPartialLoweringPattern::FuncOpPartialLoweringPattern;
2357 PatternRewriter &rewriter)
const override {
2358 rewriter.eraseOp(funcOp);
2364 PatternRewriter &rewriter)
const override {
2378 class SCFToCalyxPass :
public circt::impl::SCFToCalyxBase<SCFToCalyxPass> {
2382 void runOnOperation()
override;
2384 LogicalResult setTopLevelFunction(mlir::ModuleOp moduleOp,
2385 std::string &topLevelFunction) {
2386 if (!topLevelFunctionOpt.empty()) {
2387 if (SymbolTable::lookupSymbolIn(moduleOp, topLevelFunctionOpt) ==
2389 moduleOp.emitError() <<
"Top level function '" << topLevelFunctionOpt
2390 <<
"' not found in module.";
2393 topLevelFunction = topLevelFunctionOpt;
2397 auto funcOps = moduleOp.getOps<FuncOp>();
2398 if (std::distance(funcOps.begin(), funcOps.end()) == 1)
2399 topLevelFunction = (*funcOps.begin()).getSymName().str();
2401 moduleOp.emitError()
2402 <<
"Module contains multiple functions, but no top level "
2403 "function was set. Please see --top-level-function";
2408 return createOptNewTopLevelFn(moduleOp, topLevelFunction);
2411 struct LoweringPattern {
2412 enum class Strategy { Once, Greedy };
2421 LogicalResult labelEntryPoint(StringRef topLevelFunction) {
2425 using OpRewritePattern::OpRewritePattern;
2426 LogicalResult matchAndRewrite(mlir::ModuleOp,
2427 PatternRewriter &)
const override {
2432 ConversionTarget target(getContext());
2433 target.addLegalDialect<calyx::CalyxDialect>();
2434 target.addLegalDialect<scf::SCFDialect>();
2435 target.addIllegalDialect<hw::HWDialect>();
2436 target.addIllegalDialect<comb::CombDialect>();
2439 target.addIllegalDialect<FuncDialect>();
2440 target.addIllegalDialect<ArithDialect>();
2441 target.addLegalOp<AddIOp, SelectOp, SubIOp, CmpIOp, ShLIOp, ShRUIOp,
2442 ShRSIOp, AndIOp, XOrIOp, OrIOp, ExtUIOp, TruncIOp,
2443 CondBranchOp, BranchOp, MulIOp, DivUIOp, DivSIOp, RemUIOp,
2444 RemSIOp, ReturnOp, arith::ConstantOp, IndexCastOp, FuncOp,
2445 ExtSIOp, CallOp, AddFOp, MulFOp, CmpFOp>();
2447 RewritePatternSet legalizePatterns(&getContext());
2448 legalizePatterns.add<DummyPattern>(&getContext());
2449 DenseSet<Operation *> legalizedOps;
2450 if (applyPartialConversion(getOperation(), target,
2451 std::move(legalizePatterns))
2462 template <
typename TPattern,
typename... PatternArgs>
2463 void addOncePattern(SmallVectorImpl<LoweringPattern> &
patterns,
2464 PatternArgs &&...args) {
2465 RewritePatternSet ps(&getContext());
2468 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Once});
2471 template <
typename TPattern,
typename... PatternArgs>
2472 void addGreedyPattern(SmallVectorImpl<LoweringPattern> &
patterns,
2473 PatternArgs &&...args) {
2474 RewritePatternSet ps(&getContext());
2475 ps.add<TPattern>(&getContext(), args...);
2477 LoweringPattern{std::move(ps), LoweringPattern::Strategy::Greedy});
2480 LogicalResult runPartialPattern(RewritePatternSet &
pattern,
bool runOnce) {
2482 "Should only apply 1 partial lowering pattern at once");
2488 GreedyRewriteConfig config;
2489 config.enableRegionSimplification =
2490 mlir::GreedySimplifyRegionLevel::Disabled;
2492 config.maxIterations = 1;
2497 (void)applyPatternsAndFoldGreedily(getOperation(), std::move(
pattern),
2507 FuncOp createNewTopLevelFn(ModuleOp moduleOp, std::string &baseName) {
2508 std::string newName =
"main";
2510 if (
auto *existingMainOp = SymbolTable::lookupSymbolIn(moduleOp, newName)) {
2511 auto existingMainFunc = dyn_cast<FuncOp>(existingMainOp);
2512 if (existingMainFunc ==
nullptr) {
2513 moduleOp.emitError() <<
"Symbol 'main' exists but is not a function";
2516 unsigned counter = 0;
2517 std::string newOldName = baseName;
2518 while (SymbolTable::lookupSymbolIn(moduleOp, newOldName))
2519 newOldName = llvm::join_items(
"_", baseName, std::to_string(++counter));
2520 existingMainFunc.setName(newOldName);
2521 if (baseName ==
"main")
2522 baseName = newOldName;
2526 OpBuilder builder(moduleOp.getContext());
2527 builder.setInsertionPointToStart(moduleOp.getBody());
2529 FunctionType funcType = builder.getFunctionType({}, {});
2532 builder.create<FuncOp>(moduleOp.getLoc(), newName, funcType))
2542 void insertCallFromNewTopLevel(OpBuilder &builder, FuncOp caller,
2544 if (caller.getBody().empty()) {
2545 caller.addEntryBlock();
2548 Block *callerEntryBlock = &caller.getBody().front();
2549 builder.setInsertionPointToStart(callerEntryBlock);
2553 SmallVector<Type, 4> nonMemRefCalleeArgTypes;
2554 for (
auto arg : callee.getArguments()) {
2555 if (!isa<MemRefType>(arg.getType())) {
2556 nonMemRefCalleeArgTypes.push_back(arg.getType());
2560 for (Type type : nonMemRefCalleeArgTypes) {
2561 callerEntryBlock->addArgument(type, caller.getLoc());
2564 FunctionType callerFnType = caller.getFunctionType();
2565 SmallVector<Type, 4> updatedCallerArgTypes(
2566 caller.getFunctionType().getInputs());
2567 updatedCallerArgTypes.append(nonMemRefCalleeArgTypes.begin(),
2568 nonMemRefCalleeArgTypes.end());
2570 callerFnType.getResults()));
2572 Block *calleeFnBody = &callee.getBody().front();
2573 unsigned originalCalleeArgNum = callee.getArguments().size();
2575 SmallVector<Value, 4> extraMemRefArgs;
2576 SmallVector<Type, 4> extraMemRefArgTypes;
2577 SmallVector<Value, 4> extraMemRefOperands;
2578 SmallVector<Operation *, 4> opsToModify;
2579 for (
auto &op : callee.getBody().getOps()) {
2580 if (isa<memref::AllocaOp, memref::AllocOp, memref::GetGlobalOp>(op))
2581 opsToModify.push_back(&op);
2586 builder.setInsertionPointToEnd(callerEntryBlock);
2587 for (
auto *op : opsToModify) {
2590 TypeSwitch<Operation *>(op)
2591 .Case<memref::AllocaOp>([&](memref::AllocaOp allocaOp) {
2592 newOpRes = builder.create<memref::AllocaOp>(callee.getLoc(),
2593 allocaOp.getType());
2595 .Case<memref::AllocOp>([&](memref::AllocOp allocOp) {
2596 newOpRes = builder.create<memref::AllocOp>(callee.getLoc(),
2599 .Case<memref::GetGlobalOp>([&](memref::GetGlobalOp getGlobalOp) {
2600 newOpRes = builder.create<memref::GetGlobalOp>(
2601 caller.getLoc(), getGlobalOp.getType(), getGlobalOp.getName());
2603 .Default([&](Operation *defaultOp) {
2604 llvm::report_fatal_error(
"Unsupported operation in TypeSwitch");
2606 extraMemRefOperands.push_back(newOpRes);
2608 calleeFnBody->addArgument(newOpRes.getType(), callee.getLoc());
2609 BlockArgument newBodyArg = calleeFnBody->getArguments().back();
2610 op->getResult(0).replaceAllUsesWith(newBodyArg);
2612 extraMemRefArgs.push_back(newBodyArg);
2613 extraMemRefArgTypes.push_back(newBodyArg.getType());
2616 SmallVector<Type, 4> updatedCalleeArgTypes(
2617 callee.getFunctionType().getInputs());
2618 updatedCalleeArgTypes.append(extraMemRefArgTypes.begin(),
2619 extraMemRefArgTypes.end());
2621 callee.getFunctionType().getResults()));
2623 unsigned otherArgsCount = 0;
2624 SmallVector<Value, 4> calleeArgFnOperands;
2625 builder.setInsertionPointToStart(callerEntryBlock);
2626 for (
auto arg : callee.getArguments().take_front(originalCalleeArgNum)) {
2627 if (isa<MemRefType>(arg.getType())) {
2628 auto memrefType = cast<MemRefType>(arg.getType());
2630 builder.create<memref::AllocOp>(callee.getLoc(), memrefType);
2631 calleeArgFnOperands.push_back(allocOp);
2633 auto callerArg = callerEntryBlock->getArgument(otherArgsCount++);
2634 calleeArgFnOperands.push_back(callerArg);
2638 SmallVector<Value, 4> fnOperands;
2639 fnOperands.append(calleeArgFnOperands.begin(), calleeArgFnOperands.end());
2640 fnOperands.append(extraMemRefOperands.begin(), extraMemRefOperands.end());
2643 auto resultTypes = callee.getResultTypes();
2645 builder.setInsertionPointToEnd(callerEntryBlock);
2646 builder.create<CallOp>(caller.getLoc(), calleeName, resultTypes,
2653 LogicalResult createOptNewTopLevelFn(ModuleOp moduleOp,
2654 std::string &topLevelFunction) {
2655 auto hasMemrefArguments = [](FuncOp func) {
2657 func.getArguments().begin(), func.getArguments().end(),
2658 [](BlockArgument arg) { return isa<MemRefType>(arg.getType()); });
2664 auto funcOps = moduleOp.getOps<FuncOp>();
2665 bool hasMemrefArgsInTopLevel =
2666 std::any_of(funcOps.begin(), funcOps.end(), [&](
auto funcOp) {
2667 return funcOp.getName() == topLevelFunction &&
2668 hasMemrefArguments(funcOp);
2671 if (hasMemrefArgsInTopLevel) {
2672 auto newTopLevelFunc = createNewTopLevelFn(moduleOp, topLevelFunction);
2673 if (!newTopLevelFunc)
2676 OpBuilder builder(moduleOp.getContext());
2677 Operation *oldTopLevelFuncOp =
2678 SymbolTable::lookupSymbolIn(moduleOp, topLevelFunction);
2679 if (
auto oldTopLevelFunc = dyn_cast<FuncOp>(oldTopLevelFuncOp))
2680 insertCallFromNewTopLevel(builder, newTopLevelFunc, oldTopLevelFunc);
2682 moduleOp.emitOpError(
"Original top-level function not found!");
2685 topLevelFunction =
"main";
2692 void SCFToCalyxPass::runOnOperation() {
2697 std::string topLevelFunction;
2698 if (failed(setTopLevelFunction(getOperation(), topLevelFunction))) {
2699 signalPassFailure();
2704 if (failed(labelEntryPoint(topLevelFunction))) {
2705 signalPassFailure();
2708 loweringState = std::make_shared<calyx::CalyxLoweringState>(getOperation(),
2719 DenseMap<FuncOp, calyx::ComponentOp> funcMap;
2720 SmallVector<LoweringPattern, 8> loweringPatterns;
2724 addOncePattern<FuncOpConversion>(loweringPatterns, patternState, funcMap,
2728 addGreedyPattern<InlineExecuteRegionOpPattern>(loweringPatterns);
2730 addOncePattern<BuildParGroups>(loweringPatterns, patternState, funcMap,
2734 addOncePattern<calyx::ConvertIndexTypes>(loweringPatterns, patternState,
2738 addOncePattern<calyx::BuildBasicBlockRegs>(loweringPatterns, patternState,
2741 addOncePattern<calyx::BuildCallInstance>(loweringPatterns, patternState,
2745 addOncePattern<calyx::BuildReturnRegs>(loweringPatterns, patternState,
2751 addOncePattern<BuildWhileGroups>(loweringPatterns, patternState, funcMap,
2757 addOncePattern<BuildForGroups>(loweringPatterns, patternState, funcMap,
2760 addOncePattern<BuildIfGroups>(loweringPatterns, patternState, funcMap,
2770 addOncePattern<BuildOpGroups>(loweringPatterns, patternState, funcMap,
2776 addOncePattern<BuildControl>(loweringPatterns, patternState, funcMap,
2781 addOncePattern<calyx::InlineCombGroups>(loweringPatterns, patternState,
2786 addOncePattern<LateSSAReplacement>(loweringPatterns, patternState, funcMap,
2792 addGreedyPattern<calyx::EliminateUnusedCombGroups>(loweringPatterns);
2796 addOncePattern<calyx::RewriteMemoryAccesses>(loweringPatterns, patternState,
2801 addOncePattern<CleanupFuncOps>(loweringPatterns, patternState, funcMap,
2805 for (
auto &pat : loweringPatterns) {
2808 pat.strategy == LoweringPattern::Strategy::Once);
2811 signalPassFailure();
2818 RewritePatternSet cleanupPatterns(&getContext());
2819 cleanupPatterns.add<calyx::MultipleGroupDonePattern,
2820 calyx::NonTerminatingGroupDonePattern>(&getContext());
2821 if (failed(applyPatternsAndFoldGreedily(getOperation(),
2822 std::move(cleanupPatterns)))) {
2823 signalPassFailure();
2827 if (ciderSourceLocationMetadata) {
2830 SmallVector<Attribute, 16> sourceLocations;
2831 getOperation()->walk([&](calyx::ComponentOp component) {
2835 MLIRContext *context = getOperation()->getContext();
2836 getOperation()->setAttr(
"calyx.metadata",
2847 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.
void setFuncOpResultMapping(const DenseMap< unsigned, unsigned > &mapping)
Assign a mapping between the source funcOp result indices and the corresponding output port indices o...
std::string getUniqueName(StringRef prefix)
Returns a unique name within compOp with the provided prefix.
void registerMemoryInterface(Value memref, const calyx::MemoryInterface &memoryInterface)
Registers a memory interface as being associated with a memory identified by 'memref'.
calyx::ComponentOp getComponentOp()
Returns the calyx::ComponentOp associated with this lowering state.
void setDataField(StringRef name, llvm::json::Array data)
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...
Location getLoc() override
Holds common utilities used for scheduling when lowering to Calyx.
Location getLoc() override
Builds a control schedule by traversing the CFG of the function and associating this with the previou...
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)
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...
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
LogicalResult partiallyLowerFuncToComp(FuncOp funcOp, PatternRewriter &rewriter) const override
LogicalResult partialEval(PatternRewriter &rewriter, scf::ParallelOp scfParOp) const
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)
const DenseMap< unsigned, calyx::RegisterOp > & getResultRegs(scf::IfOp op)
DenseMap< Operation *, calyx::GroupOp > elseGroup
DenseMap< Operation *, calyx::GroupOp > thenGroup
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 * getBodyBlock() override
Block::BlockArgListType getBodyArgs() override
ScfWhileOp(scf::WhileOp op)
Block::BlockArgListType getBodyArgs() override
Block * getConditionBlock() override
std::optional< int64_t > getBound() override
Block * getBodyBlock() override
Value getConditionValue() 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)
const DenseMap< unsigned, calyx::RegisterOp > & getWhileLoopIterRegs(ScfWhileOp op)
void setWhileLoopLatchGroup(ScfWhileOp op, calyx::GroupOp group)
calyx::GroupOp getWhileLoopLatchGroup(ScfWhileOp op)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
void addMandatoryComponentPorts(PatternRewriter &rewriter, SmallVectorImpl< calyx::PortInfo > &ports)
void 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.
calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, ComponentOp component, size_t width, Twine prefix)
Creates a RegisterOp, with input and output port bit widths defined by width.
bool noStoresToMemory(Value memoryReference)
bool singleLoadFromMemory(Value memoryReference)
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 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.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
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.