28#define GEN_PASS_DEF_SCFTOCONTROLFLOWPASS
29#include "mlir/Conversion/Passes.h.inc"
37struct SCFToControlFlowPass
40 void runOnOperation()
override;
105 using OpRewritePattern<ForOp>::OpRewritePattern;
107 LogicalResult matchAndRewrite(ForOp forOp,
108 PatternRewriter &rewriter)
const override;
198 using OpRewritePattern<IfOp>::OpRewritePattern;
200 LogicalResult matchAndRewrite(IfOp ifOp,
201 PatternRewriter &rewriter)
const override;
205 using OpRewritePattern<ExecuteRegionOp>::OpRewritePattern;
207 LogicalResult matchAndRewrite(ExecuteRegionOp op,
208 PatternRewriter &rewriter)
const override;
212 using OpRewritePattern<mlir::scf::ParallelOp>::OpRewritePattern;
214 LogicalResult matchAndRewrite(mlir::scf::ParallelOp parallelOp,
215 PatternRewriter &rewriter)
const override;
281 PatternRewriter &rewriter)
const override;
289 using OpRewritePattern<WhileOp>::OpRewritePattern;
291 LogicalResult matchAndRewrite(WhileOp whileOp,
292 PatternRewriter &rewriter)
const override;
299 LogicalResult matchAndRewrite(IndexSwitchOp op,
300 PatternRewriter &rewriter)
const override;
308 using OpRewritePattern<mlir::scf::ForallOp>::OpRewritePattern;
310 LogicalResult matchAndRewrite(mlir::scf::ForallOp forallOp,
311 PatternRewriter &rewriter)
const override;
320 return isa<LLVM::LLVMDialect>(attr.getValue().getDialect());
333LogicalResult ForLowering::matchAndRewrite(ForOp forOp,
335 Location loc = forOp.getLoc();
342 auto *endBlock = rewriter.
splitBlock(initBlock, initPosition);
348 auto *conditionBlock = &forOp.getRegion().
front();
349 auto *firstBodyBlock =
350 rewriter.
splitBlock(conditionBlock, conditionBlock->begin());
351 auto *lastBodyBlock = &forOp.getRegion().
back();
353 auto iv = conditionBlock->getArgument(0);
358 Operation *terminator = lastBodyBlock->getTerminator();
360 auto step = forOp.getStep();
364 arith::IntegerOverflowFlags overflowFlags =
365 forOp.getUnsignedCmp() ? arith::IntegerOverflowFlags::nuw
366 : arith::IntegerOverflowFlags::nsw;
368 arith::AddIOp::create(rewriter, loc, iv, step, overflowFlags).getResult();
372 SmallVector<Value, 8> loopCarried;
373 loopCarried.push_back(stepped);
376 cf::BranchOp::create(rewriter, loc, conditionBlock, loopCarried);
383 Value lowerBound = forOp.getLowerBound();
384 Value upperBound = forOp.getUpperBound();
385 if (!lowerBound || !upperBound)
390 SmallVector<Value, 8> destOperands;
391 destOperands.push_back(lowerBound);
392 llvm::append_range(destOperands, forOp.getInitArgs());
393 cf::BranchOp::create(rewriter, loc, conditionBlock, destOperands);
397 arith::CmpIPredicate predicate = forOp.getUnsignedCmp()
398 ? arith::CmpIPredicate::ult
399 : arith::CmpIPredicate::slt;
401 arith::CmpIOp::create(rewriter, loc, predicate, iv, upperBound);
403 cf::CondBranchOp::create(rewriter, loc, comparison, firstBodyBlock,
404 ArrayRef<Value>(), endBlock, ArrayRef<Value>());
408 rewriter.
replaceOp(forOp, conditionBlock->getArguments().drop_front());
412LogicalResult IfLowering::matchAndRewrite(IfOp ifOp,
413 PatternRewriter &rewriter)
const {
414 auto loc = ifOp.getLoc();
421 auto *remainingOpsBlock = rewriter.
splitBlock(condBlock, opPosition);
422 Block *continueBlock;
423 if (ifOp.getNumResults() == 0) {
424 continueBlock = remainingOpsBlock;
427 rewriter.
createBlock(remainingOpsBlock, ifOp.getResultTypes(),
428 SmallVector<Location>(ifOp.getNumResults(), loc));
429 cf::BranchOp::create(rewriter, loc, remainingOpsBlock);
434 auto &thenRegion = ifOp.getThenRegion();
435 auto *thenBlock = &thenRegion.
front();
436 Operation *thenTerminator = thenRegion.back().getTerminator();
439 cf::BranchOp::create(rewriter, loc, continueBlock, thenTerminatorOperands);
440 rewriter.
eraseOp(thenTerminator);
446 auto *elseBlock = continueBlock;
447 auto &elseRegion = ifOp.getElseRegion();
448 if (!elseRegion.empty()) {
449 elseBlock = &elseRegion.front();
450 Operation *elseTerminator = elseRegion.back().getTerminator();
453 cf::BranchOp::create(rewriter, loc, continueBlock, elseTerminatorOperands);
454 rewriter.
eraseOp(elseTerminator);
459 cf::CondBranchOp::create(rewriter, loc, ifOp.getCondition(), thenBlock,
460 ArrayRef<Value>(), elseBlock,
469ExecuteRegionLowering::matchAndRewrite(ExecuteRegionOp op,
470 PatternRewriter &rewriter)
const {
471 auto loc = op.getLoc();
475 auto *remainingOpsBlock = rewriter.
splitBlock(condBlock, opPosition);
477 auto ®ion = op.getRegion();
479 cf::BranchOp::create(rewriter, loc, ®ion.front());
481 for (
Block &block : region) {
482 if (
auto terminator = dyn_cast<scf::YieldOp>(block.getTerminator())) {
485 cf::BranchOp::create(rewriter, terminator.
getLoc(), remainingOpsBlock,
493 SmallVector<Value> vals;
494 SmallVector<Location> argLocs(op.getNumResults(), op->getLoc());
496 remainingOpsBlock->addArguments(op->getResultTypes(), argLocs))
503ParallelLowering::matchAndRewrite(ParallelOp parallelOp,
504 PatternRewriter &rewriter)
const {
505 Location loc = parallelOp.getLoc();
506 auto reductionOp = dyn_cast<ReduceOp>(parallelOp.getBody()->getTerminator());
516 SmallVector<Value, 4> iterArgs = llvm::to_vector<4>(parallelOp.getInitVals());
517 SmallVector<Value, 4> ivs;
518 ivs.reserve(parallelOp.getNumLoops());
520 SmallVector<Value, 4> loopResults(iterArgs);
521 ForOp innermostForOp;
522 for (
auto [iv, lower, upper, step] :
523 llvm::zip(parallelOp.getInductionVars(), parallelOp.getLowerBound(),
524 parallelOp.getUpperBound(), parallelOp.getStep())) {
526 ForOp::create(rewriter, loc, lower, upper, step, iterArgs,
527 nullptr, parallelOp.getUnsignedCmp());
528 innermostForOp = forOp;
529 ivs.push_back(forOp.getInductionVar());
530 auto iterRange = forOp.getRegionIterArgs();
531 iterArgs.assign(iterRange.begin(), iterRange.end());
536 loopResults.assign(forOp.result_begin(), forOp.result_end());
538 }
else if (!forOp.getResults().empty()) {
542 scf::YieldOp::create(rewriter, loc, forOp.getResults());
555 SmallVector<Value> yieldOperands;
556 yieldOperands.reserve(parallelOp.getNumResults());
557 for (int64_t i = 0, e = parallelOp.getNumResults(); i < e; ++i) {
558 Block &reductionBody = reductionOp.getReductions()[i].front();
559 Value arg = iterArgs[yieldOperands.size()];
560 yieldOperands.push_back(
561 cast<ReduceReturnOp>(reductionBody.
getTerminator()).getResult());
564 {arg, reductionOp.getOperands()[i]});
570 if (newBody->
empty())
571 rewriter.
mergeBlocks(parallelOp.getBody(), newBody, ivs);
578 if (!yieldOperands.empty()) {
580 scf::YieldOp::create(rewriter, loc, yieldOperands);
583 rewriter.
replaceOp(parallelOp, loopResults);
589 PatternRewriter &rewriter)
const {
590 OpBuilder::InsertionGuard guard(rewriter);
591 Location loc = whileOp.getLoc();
595 Block *continuation =
599 Block *after = whileOp.getAfterBody();
600 Block *before = whileOp.getBeforeBody();
606 cf::BranchOp::create(rewriter, loc, before, whileOp.getInits());
613 SmallVector<Value> args = llvm::to_vector(condOp.getArgs());
615 after, condOp.getArgs(),
621 yieldOp.getResults());
632DoWhileLowering::matchAndRewrite(WhileOp whileOp,
633 PatternRewriter &rewriter)
const {
634 Block &afterBlock = *whileOp.getAfterBody();
635 if (!llvm::hasSingleElement(afterBlock))
637 "do-while simplification applicable "
638 "only if 'after' region has no payload");
640 auto yield = dyn_cast<scf::YieldOp>(&afterBlock.
front());
641 if (!yield || yield.getResults() != afterBlock.
getArguments())
643 "do-while simplification applicable "
644 "only to forwarding 'after' regions");
647 OpBuilder::InsertionGuard guard(rewriter);
649 Block *continuation =
653 Block *before = whileOp.getBeforeBody();
658 cf::BranchOp::create(rewriter, whileOp.getLoc(), before, whileOp.getInits());
663 auto latch = cf::CondBranchOp::create(
664 rewriter, condOp.getLoc(), condOp.getCondition(), before,
665 condOp.getArgs(), continuation,
ValueRange());
670 rewriter.
replaceOp(whileOp, condOp.getArgs());
678IndexSwitchLowering::matchAndRewrite(IndexSwitchOp op,
679 PatternRewriter &rewriter)
const {
686 SmallVector<Value> results;
687 results.reserve(op.getNumResults());
688 for (Type resultType : op.getResultTypes())
689 results.push_back(continueBlock->
addArgument(resultType, op.getLoc()));
692 auto convertRegion = [&](Region ®ion) -> FailureOr<Block *> {
693 Block *block = ®ion.front();
699 yield.getOperands());
707 SmallVector<Block *> caseSuccessors;
708 SmallVector<APInt> caseValues;
709 caseSuccessors.reserve(op.getCases().size());
710 caseValues.reserve(op.getCases().size());
711 for (
auto [region, value] : llvm::zip(op.getCaseRegions(), op.getCases())) {
712 FailureOr<Block *> block = convertRegion(region);
715 caseSuccessors.push_back(*block);
716 caseValues.push_back(APInt(64, value));
720 FailureOr<Block *> defaultBlock = convertRegion(op.getDefaultRegion());
726 SmallVector<ValueRange> caseOperands(caseSuccessors.size(), {});
729 Value caseValue = arith::IndexCastOp::create(
730 rewriter, op.getLoc(), rewriter.
getI64Type(), op.getArg());
732 cf::SwitchOp::create(rewriter, op.getLoc(), caseValue, *defaultBlock,
733 ValueRange(), caseValues, caseSuccessors, caseOperands);
734 rewriter.
replaceOp(op, continueBlock->getArguments());
738LogicalResult ForallLowering::matchAndRewrite(ForallOp forallOp,
739 PatternRewriter &rewriter)
const {
745 patterns.
add<ForallLowering, ForLowering, IfLowering, ParallelLowering,
751void SCFToControlFlowPass::runOnOperation() {
757 target.addIllegalOp<scf::ForallOp, scf::ForOp, scf::IfOp, scf::IndexSwitchOp,
758 scf::ParallelOp, scf::WhileOp, scf::ExecuteRegionOp>();
759 target.markUnknownOpDynamicallyLegal([](
Operation *) {
return true; });
760 ConversionConfig config;
761 config.allowPatternRollback = allowPatternRollback;
762 if (
failed(applyPartialConversion(getOperation(),
target, std::move(patterns),
static void propagateLoopAttrs(Operation *scfOp, Operation *brOp)
static void copyLLVMDialectAttrs(Operation *from, Operation *to)
OpListType::iterator iterator
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
BlockArgListType getArguments()
Block::iterator getInsertionPoint() const
Returns the current insertion point of the builder.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
Operation is the basic unit of execution within MLIR.
operand_iterator operand_begin()
Location getLoc()
The source location the operation was defined or derived from.
operand_iterator operand_end()
auto getDiscardableAttrs()
Return a range of all of discardable attributes on this operation.
operand_range getOperands()
Returns an iterator on the underlying Value's.
void setDiscardableAttrs(DictionaryAttr newAttrs)
Set the discardable attribute dictionary on this operation.
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Block * splitBlock(Block *block, Block::iterator before)
Split the operations starting at "before" (inclusive) out of the given block into a new block,...
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
void mergeBlocks(Block *source, Block *dest, ValueRange argValues={})
Inline the operations of block 'source' into the end of block 'dest'.
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
void inlineRegionBefore(Region ®ion, Region &parent, Region::iterator before)
Move the blocks that belong to "region" before the given position in another region "parent".
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
LogicalResult forallToParallelLoop(RewriterBase &rewriter, ForallOp forallOp, ParallelOp *result=nullptr)
Try converting scf.forall into an scf.parallel loop.
Include the generated interface declarations.
void populateSCFToControlFlowConversionPatterns(RewritePatternSet &patterns)
Collect a set of patterns to convert SCF operations to CFG branch-based operations within the Control...
LogicalResult matchAndRewrite(WhileOp whileOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})