clang 24.0.0git
CIRFoldEmptyBranches.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a pass that removes blocks containing only an
10// unconditional branch to a block that has no other predecessor, redirecting
11// their predecessors to the branch target.
12//
13//===----------------------------------------------------------------------===//
14
15#include "PassDetail.h"
16#include "mlir/IR/Block.h"
17#include "mlir/IR/Region.h"
18#include "mlir/Interfaces/ControlFlowInterfaces.h"
21#include "llvm/ADT/STLExtras.h"
22
23using namespace mlir;
24using namespace cir;
25
26namespace mlir {
27#define GEN_PASS_DEF_CIRFOLDEMPTYBRANCHES
28#include "clang/CIR/Dialect/Passes.h.inc"
29} // namespace mlir
30
31namespace {
32
33struct CIRFoldEmptyBranchesPass
34 : public impl::CIRFoldEmptyBranchesBase<CIRFoldEmptyBranchesPass> {
35 using CIRFoldEmptyBranchesBase::CIRFoldEmptyBranchesBase;
36
37 void runOnOperation() override;
38};
39
40/// Erase `block` if it is a non-entry block with no arguments whose only
41/// operation is a `cir.br` to another block, and `block` is the only
42/// predecessor of that block. A `cir.br` with a loop id is a loop back edge
43/// that carries the loop's metadata, so it is kept. Every predecessor
44/// terminator must implement BranchOpInterface so the `cir.br` operands can be
45/// forwarded.
46static bool foldEmptyBranch(Block &block) {
47 if (block.isEntryBlock() || block.getNumArguments() != 0 ||
48 !llvm::hasSingleElement(block))
49 return false;
50
51 auto br = dyn_cast<cir::BrOp>(block.front());
52 if (!br || br.getDest() == &block || br.getLoopIdAttr())
53 return false;
54
55 Block *dest = br.getDest();
56 if (dest->getSinglePredecessor() != &block)
57 return false;
58
59 if (!llvm::all_of(block.getPredecessors(), [](Block *pred) {
60 return isa<BranchOpInterface>(pred->getTerminator());
61 }))
62 return false;
63
64 SmallVector<Value> operands(br.getDestOperands());
65 for (BlockOperand &use : llvm::make_early_inc_range(block.getUses())) {
66 auto branch = cast<BranchOpInterface>(use.getOwner());
67 unsigned index = use.getOperandNumber();
68 branch.getSuccessorOperands(index).append(operands);
69 branch->setSuccessor(dest, index);
70 }
71 block.erase();
72 return true;
73}
74
75void CIRFoldEmptyBranchesPass::runOnOperation() {
76 getOperation()->walk([](Region *region) {
77 bool changed;
78 do {
79 changed = false;
80 for (Block &block : llvm::make_early_inc_range(*region))
81 changed |= foldEmptyBranch(block);
82 } while (changed);
83 });
84}
85
86} // namespace
87
88std::unique_ptr<Pass> mlir::createCIRFoldEmptyBranchesPass() {
89 return std::make_unique<CIRFoldEmptyBranchesPass>();
90}
std::unique_ptr< Pass > createCIRFoldEmptyBranchesPass()