10#include "mlir/Analysis/CFGLoopInfo.h"
11#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
12#include "mlir/Conversion/LLVMCommon/Pattern.h"
13#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
14#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
15#include "mlir/Dialect/Func/IR/FuncOps.h"
16#include "mlir/IR/Dominance.h"
17#include "mlir/Pass/Pass.h"
18#include "mlir/Transforms/DialectConversion.h"
19#include "llvm/ADT/TypeSwitch.h"
22#define GEN_PASS_DEF_INSERTMERGEBLOCKS
23#include "circt/Transforms/Passes.h.inc"
33 ConversionPatternRewriter &rewriter) {
34 rewriter.setInsertionPointToEnd(block);
35 auto *term = block->getTerminator();
36 return llvm::TypeSwitch<Operation *, LogicalResult>(term)
37 .Case<cf::BranchOp>([&](
auto branchOp) {
38 rewriter.replaceOpWithNewOp<cf::BranchOp>(branchOp, newDest,
39 branchOp->getOperands());
42 .Case<cf::CondBranchOp>([&](
auto condBr) {
43 auto cond = condBr.getCondition();
45 Block *trueDest = condBr.getTrueDest();
46 Block *falseDest = condBr.getFalseDest();
49 if (trueDest == oldDest)
52 if (falseDest == oldDest)
55 rewriter.replaceOpWithNewOp<cf::CondBranchOp>(
56 condBr, cond, trueDest, condBr.getTrueOperands(), falseDest,
57 condBr.getFalseOperands());
60 .Default([&](Operation *op) {
61 return op->emitError(
"Unexpected terminator that cannot be handled.");
68 ConversionPatternRewriter &rewriter) {
69 auto blockArgTypes = oldSucc->getArgumentTypes();
70 SmallVector<Location> argLocs(blockArgTypes.size(), rewriter.getUnknownLoc());
72 Block *res = rewriter.createBlock(oldSucc, blockArgTypes, argLocs);
73 cf::BranchOp::create(rewriter, rewriter.getUnknownLoc(), oldSucc,
87 DualGraph(Region &r, CFGLoopInfo &loopInfo);
89 size_t getNumPredecessors(Block *b) {
return predCnts.lookup(b); }
90 void getPredecessors(Block *b, SmallVectorImpl<Block *> &res);
92 size_t getNumSuccessors(Block *b) {
return succMap.lookup(b).size(); }
93 ArrayRef<Block *> getSuccessors(Block *b) {
94 return succMap.find(b)->getSecond();
99 Block *lookupDualBlock(Block *b);
100 DenseMap<Block *, size_t> getPredCountMapCopy() {
return predCnts; }
103 CFGLoopInfo &loopInfo;
105 DenseMap<Block *, SmallVector<Block *>> succMap;
106 DenseMap<Block *, size_t> predCnts;
110DualGraph::DualGraph(Region &r, CFGLoopInfo &loopInfo)
111 : loopInfo(loopInfo), succMap(), predCnts() {
113 CFGLoop *loop = loopInfo.getLoopFor(&b);
115 if (loop && loop->getHeader() != &b)
119 SmallVector<Block *> &succs =
120 succMap.try_emplace(&b, SmallVector<Block *>()).first->getSecond();
124 unsigned predCnt = 0;
125 for (
auto *pred : b.getPredecessors())
126 if (!loop || !loop->contains(pred))
129 if (loop && loop->getHeader() == &b)
130 loop->getExitBlocks(succs);
132 llvm::copy(b.getSuccessors(), std::back_inserter(succs));
134 predCnts.try_emplace(&b, predCnt);
138Block *DualGraph::lookupDualBlock(Block *b) {
139 CFGLoop *loop = loopInfo.getLoopFor(b);
143 return loop->getHeader();
146void DualGraph::getPredecessors(Block *b, SmallVectorImpl<Block *> &res) {
147 CFGLoop *loop = loopInfo.getLoopFor(b);
148 assert((!loop || loop->getHeader() == b) &&
149 "can only get predecessors of blocks in the graph");
151 for (
auto *pred : b->getPredecessors()) {
152 if (loop && loop->contains(pred))
155 if (CFGLoop *predLoop = loopInfo.getLoopFor(pred)) {
156 assert(predLoop->getExitBlock() &&
157 "multiple exit blocks are not yet supported");
158 res.push_back(predLoop->getHeader());
166using BlockToBlockMap = DenseMap<Block *, Block *>;
181 ConversionPatternRewriter &rewriter,
183 SmallVector<Block *> preds;
184 llvm::copy(currBlock->getPredecessors(), std::back_inserter(preds));
187 DenseMap<Block *, Block *> predsToConsider;
189 while (!preds.empty()) {
190 Block *pred = preds.pop_back_val();
191 Block *splitBlock = splitInfo.out.lookup(graph.lookupDualBlock(pred));
192 if (splitBlock == predDom)
197 if (predsToConsider.count(splitBlock) == 0) {
200 predsToConsider.try_emplace(splitBlock, pred);
205 Block *other = predsToConsider.lookup(splitBlock);
206 predsToConsider.erase(splitBlock);
214 Block *splitIn = splitInfo.in.lookup(splitBlock);
215 splitInfo.in.try_emplace(*
mergeBlock, splitIn);
217 splitInfo.out.try_emplace(*
mergeBlock, splitIn);
221 if (!predsToConsider.empty())
222 return currBlock->getParentOp()->emitError(
223 "irregular control flow is not yet supported");
229 for (
auto &info : loopInfo.getTopLevelLoops())
231 if (!info->getExitBlock())
232 return r.getParentOp()->emitError(
233 "multiple exit blocks are not yet supported");
247 ConversionPatternRewriter &rewriter) {
248 Block *entry = &r.front();
249 DominanceInfo domInfo(r.getParentOp());
251 CFGLoopInfo loopInfo(domInfo.getDomTree(&r));
256 SmallVector<Block *> stack;
257 stack.push_back(entry);
261 DualGraph graph(r, loopInfo);
264 auto predsToVisit = graph.getPredCountMapCopy();
268 while (!stack.empty()) {
269 Block *currBlock = stack.pop_back_val();
272 Block *out =
nullptr;
274 bool isMergeBlock = graph.getNumPredecessors(currBlock) > 1;
275 bool isSplitBlock = graph.getNumSuccessors(currBlock) > 1;
277 SmallVector<Block *> preds;
278 graph.getPredecessors(currBlock, preds);
281 Block *predDom = currBlock;
282 for (
auto *pred : preds) {
283 predDom = domInfo.findNearestCommonDominator(predDom, pred);
293 in = splitInfo.in.lookup(predDom);
294 }
else if (!preds.empty()) {
295 Block *pred = preds.front();
297 in = splitInfo.out.lookup(pred);
305 splitInfo.in.try_emplace(currBlock, in);
306 splitInfo.out.try_emplace(currBlock, out);
308 for (
auto *succ : graph.getSuccessors(currBlock)) {
309 auto it = predsToVisit.find(succ);
310 unsigned predsRemaining = --(it->getSecond());
313 if (predsRemaining == 0)
314 stack.push_back(succ);
323using PtrSet = SmallPtrSet<Operation *, 4>;
325struct FuncOpPattern :
public OpConversionPattern<func::FuncOp> {
327 FuncOpPattern(PtrSet &rewrittenFuncs, MLIRContext *ctx)
328 : OpConversionPattern(ctx), rewrittenFuncs(rewrittenFuncs) {}
331 matchAndRewrite(func::FuncOp op, OpAdaptor adaptor,
332 ConversionPatternRewriter &rewriter)
const override {
333 rewriter.startOpModification(op);
335 if (!op.isExternal())
337 rewriter.cancelOpModification(op);
341 rewriter.finalizeOpModification(op);
342 rewrittenFuncs.insert(op);
348 PtrSet &rewrittenFuncs;
351struct InsertMergeBlocksPass
352 :
public circt::impl::InsertMergeBlocksBase<InsertMergeBlocksPass> {
354 void runOnOperation()
override {
355 auto *ctx = &getContext();
356 RewritePatternSet patterns(ctx);
358 PtrSet rewrittenFuncs;
359 patterns.add<FuncOpPattern>(rewrittenFuncs, ctx);
361 ConversionTarget target(*ctx);
362 target.addDynamicallyLegalOp<func::FuncOp>(
363 [&](func::FuncOp func) {
return rewrittenFuncs.contains(func); });
364 target.addLegalDialect<cf::ControlFlowDialect>();
366 if (applyPartialConversion(getOperation(), target, std::move(patterns))
376 return std::make_unique<InsertMergeBlocksPass>();
assert(baseType &&"element must be base type")
static void mergeBlock(Block &destination, Block::iterator insertPoint, Block &source)
Move all operations from a source block in to a destination block.
static LogicalResult changeBranchTarget(Block *block, Block *oldDest, Block *newDest, ConversionPatternRewriter &rewriter)
Replaces the branching to oldDest of with an equivalent operation that instead branches to newDest.
static FailureOr< Block * > buildMergeBlock(Block *b1, Block *b2, Block *oldSucc, ConversionPatternRewriter &rewriter)
Creates a new intermediate block that b1 and b2 branch to.
static LogicalResult preconditionCheck(Region &r, CFGLoopInfo &loopInfo)
Checks preconditions of this transformation.
static LogicalResult buildMergeBlocks(Block *currBlock, SplitInfo &splitInfo, Block *predDom, ConversionPatternRewriter &rewriter, DualGraph &graph)
Builds a binary merge block tree for the predecessors of currBlock.
false return failure()
Parse an optional keyword or string and set instance into 'result'.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createInsertMergeBlocksPass()
mlir::LogicalResult insertMergeBlocks(mlir::Region &r, mlir::ConversionPatternRewriter &rewriter)
Insert additional blocks that serve as counterparts to the blocks that diverged the control flow.