165 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements pass that canonicalizes CIR operations, eliminating10// redundant branches, empty scopes, and other unnecessary operations.11//12//===----------------------------------------------------------------------===//13 14#include "PassDetail.h"15#include "mlir/Dialect/Func/IR/FuncOps.h"16#include "mlir/IR/Block.h"17#include "mlir/IR/Operation.h"18#include "mlir/IR/PatternMatch.h"19#include "mlir/IR/Region.h"20#include "mlir/Support/LogicalResult.h"21#include "mlir/Transforms/GreedyPatternRewriteDriver.h"22#include "clang/CIR/Dialect/IR/CIRDialect.h"23#include "clang/CIR/Dialect/Passes.h"24#include "clang/CIR/MissingFeatures.h"25 26using namespace mlir;27using namespace cir;28 29namespace mlir {30#define GEN_PASS_DEF_CIRCANONICALIZE31#include "clang/CIR/Dialect/Passes.h.inc"32} // namespace mlir33 34namespace {35 36/// Removes branches between two blocks if it is the only branch.37///38/// From:39/// ^bb0:40/// cir.br ^bb141/// ^bb1: // pred: ^bb042/// cir.return43///44/// To:45/// ^bb0:46/// cir.return47struct RemoveRedundantBranches : public OpRewritePattern<BrOp> {48 using OpRewritePattern<BrOp>::OpRewritePattern;49 50 LogicalResult matchAndRewrite(BrOp op,51 PatternRewriter &rewriter) const final {52 Block *block = op.getOperation()->getBlock();53 Block *dest = op.getDest();54 55 if (isa<cir::LabelOp>(dest->front()))56 return failure();57 // Single edge between blocks: merge it.58 if (block->getNumSuccessors() == 1 &&59 dest->getSinglePredecessor() == block) {60 rewriter.eraseOp(op);61 rewriter.mergeBlocks(dest, block);62 return success();63 }64 65 return failure();66 }67};68 69struct RemoveEmptyScope : public OpRewritePattern<ScopeOp> {70 using OpRewritePattern<ScopeOp>::OpRewritePattern;71 72 LogicalResult matchAndRewrite(ScopeOp op,73 PatternRewriter &rewriter) const final {74 // TODO: Remove this logic once CIR uses MLIR infrastructure to remove75 // trivially dead operations76 if (op.isEmpty()) {77 rewriter.eraseOp(op);78 return success();79 }80 81 Region ®ion = op.getScopeRegion();82 if (region.getBlocks().front().getOperations().size() == 1 &&83 isa<YieldOp>(region.getBlocks().front().front())) {84 rewriter.eraseOp(op);85 return success();86 }87 88 return failure();89 }90};91 92struct RemoveEmptySwitch : public OpRewritePattern<SwitchOp> {93 using OpRewritePattern<SwitchOp>::OpRewritePattern;94 95 LogicalResult matchAndRewrite(SwitchOp op,96 PatternRewriter &rewriter) const final {97 if (!(op.getBody().empty() || isa<YieldOp>(op.getBody().front().front())))98 return failure();99 100 rewriter.eraseOp(op);101 return success();102 }103};104 105//===----------------------------------------------------------------------===//106// CIRCanonicalizePass107//===----------------------------------------------------------------------===//108 109struct CIRCanonicalizePass110 : public impl::CIRCanonicalizeBase<CIRCanonicalizePass> {111 using CIRCanonicalizeBase::CIRCanonicalizeBase;112 113 // The same operation rewriting done here could have been performed114 // by CanonicalizerPass (adding hasCanonicalizer for target Ops and115 // implementing the same from above in CIRDialects.cpp). However, it's116 // currently too aggressive for static analysis purposes, since it might117 // remove things where a diagnostic can be generated.118 //119 // FIXME: perhaps we can add one more mode to GreedyRewriteConfig to120 // disable this behavior.121 void runOnOperation() override;122};123 124void populateCIRCanonicalizePatterns(RewritePatternSet &patterns) {125 // clang-format off126 patterns.add<127 RemoveRedundantBranches,128 RemoveEmptyScope129 >(patterns.getContext());130 // clang-format on131}132 133void CIRCanonicalizePass::runOnOperation() {134 // Collect rewrite patterns.135 RewritePatternSet patterns(&getContext());136 populateCIRCanonicalizePatterns(patterns);137 138 // Collect operations to apply patterns.139 llvm::SmallVector<Operation *, 16> ops;140 getOperation()->walk([&](Operation *op) {141 assert(!cir::MissingFeatures::switchOp());142 assert(!cir::MissingFeatures::tryOp());143 assert(!cir::MissingFeatures::callOp());144 145 // Many operations are here to perform a manual `fold` in146 // applyOpPatternsGreedily.147 if (isa<BrOp, BrCondOp, CastOp, ScopeOp, SwitchOp, SelectOp, UnaryOp,148 ComplexCreateOp, ComplexImagOp, ComplexRealOp, VecCmpOp,149 VecCreateOp, VecExtractOp, VecShuffleOp, VecShuffleDynamicOp,150 VecTernaryOp, BitClrsbOp, BitClzOp, BitCtzOp, BitFfsOp, BitParityOp,151 BitPopcountOp, BitReverseOp, ByteSwapOp, RotateOp>(op))152 ops.push_back(op);153 });154 155 // Apply patterns.156 if (applyOpPatternsGreedily(ops, std::move(patterns)).failed())157 signalPassFailure();158}159 160} // namespace161 162std::unique_ptr<Pass> mlir::createCIRCanonicalizePass() {163 return std::make_unique<CIRCanonicalizePass>();164}165