10#include "mlir/Dialect/Func/IR/FuncOps.h"
11#include "mlir/IR/Block.h"
12#include "mlir/IR/Dominance.h"
13#include "mlir/IR/Operation.h"
14#include "mlir/IR/PatternMatch.h"
15#include "mlir/IR/Region.h"
16#include "mlir/Support/LogicalResult.h"
17#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
20#include "llvm/ADT/SmallVector.h"
26#define GEN_PASS_DEF_CIRSIMPLIFY
27#include "clang/CIR/Dialect/Passes.h.inc"
41class RewriteDominanceInfo final :
public RewriterBase::Listener {
43 DominanceInfo &getDominanceInfo() {
return domInfo; }
45 void notifyBlockInserted(
Block *block, Region *previous,
46 Region::iterator previousIt)
override {
47 domInfo.invalidate(block->getParent(),
false);
49 domInfo.invalidate(previous,
false);
52 void notifyBlockErased(
Block *block)
override {
53 domInfo.invalidate(block->getParent(),
false);
57 DominanceInfo domInfo;
66cir::StoreOp findDominatingInitOp(cir::AllocaOp alloca, cir::LoadOp load,
67 const DominanceInfo &domInfo) {
72 for (
const mlir::OpOperand &use : alloca->getUses()) {
73 auto store = mlir::dyn_cast<cir::StoreOp>(use.getOwner());
80 if (use.getOperandNumber() != cir::StoreOp::odsIndex_addr)
83 if (domInfo.dominates(store, load)) {
105struct SimplifyConstantLoad final :
public OpRewritePattern<LoadOp> {
106 SimplifyConstantLoad(MLIRContext *context, RewriteDominanceInfo &domInfo)
107 : OpRewritePattern(context), domInfo(domInfo) {}
109 LogicalResult matchAndRewrite(LoadOp op,
110 PatternRewriter &rewriter)
const override {
112 if (op.getIsVolatile() || op.getMemOrder())
113 return mlir::failure();
115 auto allocaOp = op.getAddr().getDefiningOp<cir::AllocaOp>();
116 if (!allocaOp || !allocaOp.getConstant())
117 return mlir::failure();
119 cir::StoreOp initStoreOp =
120 findDominatingInitOp(allocaOp, op, domInfo.getDominanceInfo());
122 return mlir::failure();
123 if (initStoreOp.getIsVolatile() || initStoreOp.getMemOrder()) {
126 return mlir::failure();
129 rewriter.replaceOp(op, initStoreOp.getValue());
130 return mlir::success();
134 RewriteDominanceInfo &domInfo;
158struct SimplifyTernary final :
public OpRewritePattern<TernaryOp> {
159 using OpRewritePattern<TernaryOp>::OpRewritePattern;
161 LogicalResult matchAndRewrite(TernaryOp op,
162 PatternRewriter &rewriter)
const override {
163 if (op->getNumResults() != 1)
164 return mlir::failure();
166 if (!isSimpleTernaryBranch(op.getTrueRegion()) ||
167 !isSimpleTernaryBranch(op.getFalseRegion()))
168 return mlir::failure();
170 cir::YieldOp trueBranchYieldOp =
171 mlir::cast<cir::YieldOp>(op.getTrueRegion().front().getTerminator());
172 cir::YieldOp falseBranchYieldOp =
173 mlir::cast<cir::YieldOp>(op.getFalseRegion().front().getTerminator());
174 mlir::Value trueValue = trueBranchYieldOp.getArgs()[0];
175 mlir::Value falseValue = falseBranchYieldOp.getArgs()[0];
177 rewriter.inlineBlockBefore(&op.getTrueRegion().front(), op);
178 rewriter.inlineBlockBefore(&op.getFalseRegion().front(), op);
179 rewriter.eraseOp(trueBranchYieldOp);
180 rewriter.eraseOp(falseBranchYieldOp);
181 rewriter.replaceOpWithNewOp<cir::SelectOp>(op, op.getCond(), trueValue,
184 return mlir::success();
188 bool isSimpleTernaryBranch(mlir::Region ®ion)
const {
189 if (!region.hasOneBlock())
192 mlir::Block &onlyBlock = region.front();
193 mlir::Block::OpListType &ops = onlyBlock.getOperations();
199 if (ops.size() == 1) {
206 auto yieldOp = mlir::cast<cir::YieldOp>(onlyBlock.getTerminator());
207 auto yieldValueDefOp =
208 yieldOp.getArgs()[0].getDefiningOp<cir::ConstantOp>();
209 return yieldValueDefOp && yieldValueDefOp->getBlock() == &onlyBlock;
231struct SimplifySelect :
public OpRewritePattern<SelectOp> {
232 using OpRewritePattern<SelectOp>::OpRewritePattern;
234 LogicalResult matchAndRewrite(SelectOp op,
235 PatternRewriter &rewriter)
const final {
236 auto trueValueOp = op.getTrueValue().getDefiningOp<cir::ConstantOp>();
237 auto falseValueOp = op.getFalseValue().getDefiningOp<cir::ConstantOp>();
238 if (!trueValueOp || !falseValueOp)
239 return mlir::failure();
241 auto trueValue = trueValueOp.getValueAttr<cir::BoolAttr>();
242 auto falseValue = falseValueOp.getValueAttr<cir::BoolAttr>();
243 if (!trueValue || !falseValue)
244 return mlir::failure();
247 if (trueValue.getValue() && !falseValue.getValue()) {
248 rewriter.replaceAllUsesWith(op, op.getCondition());
249 rewriter.eraseOp(op);
250 return mlir::success();
254 if (!trueValue.getValue() && falseValue.getValue()) {
255 rewriter.replaceOpWithNewOp<cir::NotOp>(op, op.getCondition());
256 return mlir::success();
259 return mlir::failure();
295struct SimplifySwitch :
public OpRewritePattern<SwitchOp> {
296 using OpRewritePattern<SwitchOp>::OpRewritePattern;
297 LogicalResult matchAndRewrite(SwitchOp op,
298 PatternRewriter &rewriter)
const override {
300 LogicalResult changed = mlir::failure();
301 SmallVector<CaseOp, 8> cases;
302 SmallVector<CaseOp, 4> cascadingCases;
303 SmallVector<mlir::Attribute, 4> cascadingCaseValues;
305 op.collectCases(cases);
307 return mlir::failure();
309 auto resetMergeState = [&]() {
310 cascadingCases.clear();
311 cascadingCaseValues.clear();
314 auto flushMergedOps = [&]() {
315 for (CaseOp &c : cascadingCases)
320 auto mergeCascadingInto = [&](CaseOp &target) {
321 rewriter.modifyOpInPlace(target, [&]() {
322 target.setValueAttr(rewriter.getArrayAttr(cascadingCaseValues));
323 target.setKind(CaseOpKind::Anyof);
325 changed = mlir::success();
331 auto mergeLastCascadingAndFlush = [&]() {
333 CaseOp lastCascadingCase = cascadingCases.back();
334 mergeCascadingInto(lastCascadingCase);
335 cascadingCases.pop_back();
339 for (CaseOp c : cases) {
345 bool isAdjacentToLastCascadingCase =
346 !cascadingCases.empty() &&
347 c->getPrevNode() == cascadingCases.back().getOperation();
349 if (!cascadingCases.empty() && !isAdjacentToLastCascadingCase) {
350 if (cascadingCases.size() > 1)
351 mergeLastCascadingAndFlush();
356 cir::CaseOpKind
kind = c.getKind();
357 if (
kind == cir::CaseOpKind::Equal &&
358 isa<YieldOp>(c.getCaseRegion().front().front())) {
360 cascadingCases.push_back(c);
361 cascadingCaseValues.push_back(c.getValue()[0]);
362 }
else if (
kind == cir::CaseOpKind::Equal && !cascadingCases.empty()) {
364 cascadingCaseValues.push_back(c.getValue()[0]);
365 mergeCascadingInto(c);
367 }
else if (
kind != cir::CaseOpKind::Equal && cascadingCases.size() > 1) {
372 mergeLastCascadingAndFlush();
379 if (cascadingCases.size() == cases.size())
380 mergeLastCascadingAndFlush();
386struct SimplifyVecSplat :
public OpRewritePattern<VecSplatOp> {
387 using OpRewritePattern<VecSplatOp>::OpRewritePattern;
388 LogicalResult matchAndRewrite(VecSplatOp op,
389 PatternRewriter &rewriter)
const override {
390 mlir::Value splatValue = op.getValue();
391 auto constant = splatValue.getDefiningOp<cir::ConstantOp>();
393 return mlir::failure();
395 auto value = constant.getValue();
396 if (!mlir::isa_and_nonnull<cir::IntAttr>(value) &&
397 !mlir::isa_and_nonnull<cir::FPAttr>(value))
398 return mlir::failure();
403 auto resultType = mlir::dyn_cast<cir::VectorType>(op.getResult().getType());
404 if (!resultType || resultType.isScalable())
405 return mlir::failure();
406 SmallVector<mlir::Attribute, 16> elements(resultType.getFixedSize(), value);
407 auto constVecAttr = cir::ConstVectorAttr::get(
408 resultType, mlir::ArrayAttr::get(getContext(), elements));
410 rewriter.replaceOpWithNewOp<cir::ConstantOp>(op, constVecAttr);
411 return mlir::success();
419struct CIRSimplifyPass :
public impl::CIRSimplifyBase<CIRSimplifyPass> {
420 using CIRSimplifyBase::CIRSimplifyBase;
422 void runOnOperation()
override;
425void populateMergeCleanupPatterns(RewritePatternSet &patterns,
426 RewriteDominanceInfo &domInfo) {
433 >(patterns.getContext());
435 patterns.add<SimplifyConstantLoad>(patterns.getContext(), domInfo);
438void CIRSimplifyPass::runOnOperation() {
441 RewriteDominanceInfo domInfo;
442 RewritePatternSet patterns(&getContext());
443 populateMergeCleanupPatterns(patterns, domInfo);
446 llvm::SmallVector<Operation *, 16> ops;
447 getOperation()->walk([&](Operation *op) {
448 if (isa<TernaryOp, SelectOp, SwitchOp, VecSplatOp, LoadOp>(op))
454 GreedyRewriteConfig config;
455 config.setScope(&getOperation()->getRegion(0));
456 config.setListener(&domInfo);
457 if (applyOpPatternsGreedily(ops, std::move(patterns), config).failed())
464 return std::make_unique<CIRSimplifyPass>();
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
std::unique_ptr< Pass > createCIRSimplifyPass()
static bool foldRangeCase()