1ace01605SRiver Riddle //===- ControlFlowOps.cpp - ControlFlow Operations ------------------------===// 2ace01605SRiver Riddle // 3ace01605SRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ace01605SRiver Riddle // See https://llvm.org/LICENSE.txt for license information. 5ace01605SRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ace01605SRiver Riddle // 7ace01605SRiver Riddle //===----------------------------------------------------------------------===// 8ace01605SRiver Riddle 9ace01605SRiver Riddle #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" 10ace01605SRiver Riddle 11ace01605SRiver Riddle #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 12ace01605SRiver Riddle #include "mlir/Dialect/CommonFolders.h" 13ace01605SRiver Riddle #include "mlir/IR/AffineExpr.h" 14ace01605SRiver Riddle #include "mlir/IR/AffineMap.h" 15ace01605SRiver Riddle #include "mlir/IR/BlockAndValueMapping.h" 16ace01605SRiver Riddle #include "mlir/IR/Builders.h" 17ace01605SRiver Riddle #include "mlir/IR/BuiltinOps.h" 18ace01605SRiver Riddle #include "mlir/IR/BuiltinTypes.h" 19ace01605SRiver Riddle #include "mlir/IR/Matchers.h" 20ace01605SRiver Riddle #include "mlir/IR/OpImplementation.h" 21ace01605SRiver Riddle #include "mlir/IR/PatternMatch.h" 22ace01605SRiver Riddle #include "mlir/IR/TypeUtilities.h" 23ace01605SRiver Riddle #include "mlir/IR/Value.h" 24ace01605SRiver Riddle #include "mlir/Support/MathExtras.h" 25ace01605SRiver Riddle #include "mlir/Transforms/InliningUtils.h" 26ace01605SRiver Riddle #include "llvm/ADT/APFloat.h" 27ace01605SRiver Riddle #include "llvm/ADT/STLExtras.h" 28ace01605SRiver Riddle #include "llvm/ADT/StringSwitch.h" 29ace01605SRiver Riddle #include "llvm/Support/FormatVariadic.h" 30ace01605SRiver Riddle #include "llvm/Support/raw_ostream.h" 31ace01605SRiver Riddle #include <numeric> 32ace01605SRiver Riddle 33ace01605SRiver Riddle #include "mlir/Dialect/ControlFlow/IR/ControlFlowOpsDialect.cpp.inc" 34ace01605SRiver Riddle 35ace01605SRiver Riddle using namespace mlir; 36ace01605SRiver Riddle using namespace mlir::cf; 37ace01605SRiver Riddle 38ace01605SRiver Riddle //===----------------------------------------------------------------------===// 39ace01605SRiver Riddle // ControlFlowDialect Interfaces 40ace01605SRiver Riddle //===----------------------------------------------------------------------===// 41ace01605SRiver Riddle namespace { 42ace01605SRiver Riddle /// This class defines the interface for handling inlining with control flow 43ace01605SRiver Riddle /// operations. 44ace01605SRiver Riddle struct ControlFlowInlinerInterface : public DialectInlinerInterface { 45ace01605SRiver Riddle using DialectInlinerInterface::DialectInlinerInterface; 46ace01605SRiver Riddle ~ControlFlowInlinerInterface() override = default; 47ace01605SRiver Riddle 48ace01605SRiver Riddle /// All control flow operations can be inlined. 49ace01605SRiver Riddle bool isLegalToInline(Operation *call, Operation *callable, 50ace01605SRiver Riddle bool wouldBeCloned) const final { 51ace01605SRiver Riddle return true; 52ace01605SRiver Riddle } 53ace01605SRiver Riddle bool isLegalToInline(Operation *, Region *, bool, 54ace01605SRiver Riddle BlockAndValueMapping &) const final { 55ace01605SRiver Riddle return true; 56ace01605SRiver Riddle } 57ace01605SRiver Riddle 58ace01605SRiver Riddle /// ControlFlow terminator operations don't really need any special handing. 59ace01605SRiver Riddle void handleTerminator(Operation *op, Block *newDest) const final {} 60ace01605SRiver Riddle }; 61ace01605SRiver Riddle } // namespace 62ace01605SRiver Riddle 63ace01605SRiver Riddle //===----------------------------------------------------------------------===// 64ace01605SRiver Riddle // ControlFlowDialect 65ace01605SRiver Riddle //===----------------------------------------------------------------------===// 66ace01605SRiver Riddle 67ace01605SRiver Riddle void ControlFlowDialect::initialize() { 68ace01605SRiver Riddle addOperations< 69ace01605SRiver Riddle #define GET_OP_LIST 70ace01605SRiver Riddle #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.cpp.inc" 71ace01605SRiver Riddle >(); 72ace01605SRiver Riddle addInterfaces<ControlFlowInlinerInterface>(); 73ace01605SRiver Riddle } 74ace01605SRiver Riddle 75ace01605SRiver Riddle //===----------------------------------------------------------------------===// 76ace01605SRiver Riddle // AssertOp 77ace01605SRiver Riddle //===----------------------------------------------------------------------===// 78ace01605SRiver Riddle 79ace01605SRiver Riddle LogicalResult AssertOp::canonicalize(AssertOp op, PatternRewriter &rewriter) { 80ace01605SRiver Riddle // Erase assertion if argument is constant true. 81ace01605SRiver Riddle if (matchPattern(op.getArg(), m_One())) { 82ace01605SRiver Riddle rewriter.eraseOp(op); 83ace01605SRiver Riddle return success(); 84ace01605SRiver Riddle } 85ace01605SRiver Riddle return failure(); 86ace01605SRiver Riddle } 87ace01605SRiver Riddle 88ace01605SRiver Riddle //===----------------------------------------------------------------------===// 89ace01605SRiver Riddle // BranchOp 90ace01605SRiver Riddle //===----------------------------------------------------------------------===// 91ace01605SRiver Riddle 92ace01605SRiver Riddle /// Given a successor, try to collapse it to a new destination if it only 93ace01605SRiver Riddle /// contains a passthrough unconditional branch. If the successor is 94ace01605SRiver Riddle /// collapsable, `successor` and `successorOperands` are updated to reference 95ace01605SRiver Riddle /// the new destination and values. `argStorage` is used as storage if operands 96ace01605SRiver Riddle /// to the collapsed successor need to be remapped. It must outlive uses of 97ace01605SRiver Riddle /// successorOperands. 98ace01605SRiver Riddle static LogicalResult collapseBranch(Block *&successor, 99ace01605SRiver Riddle ValueRange &successorOperands, 100ace01605SRiver Riddle SmallVectorImpl<Value> &argStorage) { 101ace01605SRiver Riddle // Check that the successor only contains a unconditional branch. 102ace01605SRiver Riddle if (std::next(successor->begin()) != successor->end()) 103ace01605SRiver Riddle return failure(); 104ace01605SRiver Riddle // Check that the terminator is an unconditional branch. 105ace01605SRiver Riddle BranchOp successorBranch = dyn_cast<BranchOp>(successor->getTerminator()); 106ace01605SRiver Riddle if (!successorBranch) 107ace01605SRiver Riddle return failure(); 108ace01605SRiver Riddle // Check that the arguments are only used within the terminator. 109ace01605SRiver Riddle for (BlockArgument arg : successor->getArguments()) { 110ace01605SRiver Riddle for (Operation *user : arg.getUsers()) 111ace01605SRiver Riddle if (user != successorBranch) 112ace01605SRiver Riddle return failure(); 113ace01605SRiver Riddle } 114ace01605SRiver Riddle // Don't try to collapse branches to infinite loops. 115ace01605SRiver Riddle Block *successorDest = successorBranch.getDest(); 116ace01605SRiver Riddle if (successorDest == successor) 117ace01605SRiver Riddle return failure(); 118ace01605SRiver Riddle 119ace01605SRiver Riddle // Update the operands to the successor. If the branch parent has no 120ace01605SRiver Riddle // arguments, we can use the branch operands directly. 121ace01605SRiver Riddle OperandRange operands = successorBranch.getOperands(); 122ace01605SRiver Riddle if (successor->args_empty()) { 123ace01605SRiver Riddle successor = successorDest; 124ace01605SRiver Riddle successorOperands = operands; 125ace01605SRiver Riddle return success(); 126ace01605SRiver Riddle } 127ace01605SRiver Riddle 128ace01605SRiver Riddle // Otherwise, we need to remap any argument operands. 129ace01605SRiver Riddle for (Value operand : operands) { 130ace01605SRiver Riddle BlockArgument argOperand = operand.dyn_cast<BlockArgument>(); 131ace01605SRiver Riddle if (argOperand && argOperand.getOwner() == successor) 132ace01605SRiver Riddle argStorage.push_back(successorOperands[argOperand.getArgNumber()]); 133ace01605SRiver Riddle else 134ace01605SRiver Riddle argStorage.push_back(operand); 135ace01605SRiver Riddle } 136ace01605SRiver Riddle successor = successorDest; 137ace01605SRiver Riddle successorOperands = argStorage; 138ace01605SRiver Riddle return success(); 139ace01605SRiver Riddle } 140ace01605SRiver Riddle 141ace01605SRiver Riddle /// Simplify a branch to a block that has a single predecessor. This effectively 142ace01605SRiver Riddle /// merges the two blocks. 143ace01605SRiver Riddle static LogicalResult 144ace01605SRiver Riddle simplifyBrToBlockWithSinglePred(BranchOp op, PatternRewriter &rewriter) { 145ace01605SRiver Riddle // Check that the successor block has a single predecessor. 146ace01605SRiver Riddle Block *succ = op.getDest(); 147ace01605SRiver Riddle Block *opParent = op->getBlock(); 148ace01605SRiver Riddle if (succ == opParent || !llvm::hasSingleElement(succ->getPredecessors())) 149ace01605SRiver Riddle return failure(); 150ace01605SRiver Riddle 151ace01605SRiver Riddle // Merge the successor into the current block and erase the branch. 152ace01605SRiver Riddle rewriter.mergeBlocks(succ, opParent, op.getOperands()); 153ace01605SRiver Riddle rewriter.eraseOp(op); 154ace01605SRiver Riddle return success(); 155ace01605SRiver Riddle } 156ace01605SRiver Riddle 157ace01605SRiver Riddle /// br ^bb1 158ace01605SRiver Riddle /// ^bb1 159ace01605SRiver Riddle /// br ^bbN(...) 160ace01605SRiver Riddle /// 161ace01605SRiver Riddle /// -> br ^bbN(...) 162ace01605SRiver Riddle /// 163ace01605SRiver Riddle static LogicalResult simplifyPassThroughBr(BranchOp op, 164ace01605SRiver Riddle PatternRewriter &rewriter) { 165ace01605SRiver Riddle Block *dest = op.getDest(); 166ace01605SRiver Riddle ValueRange destOperands = op.getOperands(); 167ace01605SRiver Riddle SmallVector<Value, 4> destOperandStorage; 168ace01605SRiver Riddle 169ace01605SRiver Riddle // Try to collapse the successor if it points somewhere other than this 170ace01605SRiver Riddle // block. 171ace01605SRiver Riddle if (dest == op->getBlock() || 172ace01605SRiver Riddle failed(collapseBranch(dest, destOperands, destOperandStorage))) 173ace01605SRiver Riddle return failure(); 174ace01605SRiver Riddle 175ace01605SRiver Riddle // Create a new branch with the collapsed successor. 176ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(op, dest, destOperands); 177ace01605SRiver Riddle return success(); 178ace01605SRiver Riddle } 179ace01605SRiver Riddle 180ace01605SRiver Riddle LogicalResult BranchOp::canonicalize(BranchOp op, PatternRewriter &rewriter) { 181ace01605SRiver Riddle return success(succeeded(simplifyBrToBlockWithSinglePred(op, rewriter)) || 182ace01605SRiver Riddle succeeded(simplifyPassThroughBr(op, rewriter))); 183ace01605SRiver Riddle } 184ace01605SRiver Riddle 185ace01605SRiver Riddle void BranchOp::setDest(Block *block) { return setSuccessor(block); } 186ace01605SRiver Riddle 187ace01605SRiver Riddle void BranchOp::eraseOperand(unsigned index) { (*this)->eraseOperand(index); } 188ace01605SRiver Riddle 189ace01605SRiver Riddle Optional<MutableOperandRange> 190ace01605SRiver Riddle BranchOp::getMutableSuccessorOperands(unsigned index) { 191ace01605SRiver Riddle assert(index == 0 && "invalid successor index"); 192ace01605SRiver Riddle return getDestOperandsMutable(); 193ace01605SRiver Riddle } 194ace01605SRiver Riddle 195ace01605SRiver Riddle Block *BranchOp::getSuccessorForOperands(ArrayRef<Attribute>) { 196ace01605SRiver Riddle return getDest(); 197ace01605SRiver Riddle } 198ace01605SRiver Riddle 199ace01605SRiver Riddle //===----------------------------------------------------------------------===// 200ace01605SRiver Riddle // CondBranchOp 201ace01605SRiver Riddle //===----------------------------------------------------------------------===// 202ace01605SRiver Riddle 203ace01605SRiver Riddle namespace { 204ace01605SRiver Riddle /// cf.cond_br true, ^bb1, ^bb2 205ace01605SRiver Riddle /// -> br ^bb1 206ace01605SRiver Riddle /// cf.cond_br false, ^bb1, ^bb2 207ace01605SRiver Riddle /// -> br ^bb2 208ace01605SRiver Riddle /// 209ace01605SRiver Riddle struct SimplifyConstCondBranchPred : public OpRewritePattern<CondBranchOp> { 210ace01605SRiver Riddle using OpRewritePattern<CondBranchOp>::OpRewritePattern; 211ace01605SRiver Riddle 212ace01605SRiver Riddle LogicalResult matchAndRewrite(CondBranchOp condbr, 213ace01605SRiver Riddle PatternRewriter &rewriter) const override { 214ace01605SRiver Riddle if (matchPattern(condbr.getCondition(), m_NonZero())) { 215ace01605SRiver Riddle // True branch taken. 216ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, condbr.getTrueDest(), 217ace01605SRiver Riddle condbr.getTrueOperands()); 218ace01605SRiver Riddle return success(); 219ace01605SRiver Riddle } 220ace01605SRiver Riddle if (matchPattern(condbr.getCondition(), m_Zero())) { 221ace01605SRiver Riddle // False branch taken. 222ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, condbr.getFalseDest(), 223ace01605SRiver Riddle condbr.getFalseOperands()); 224ace01605SRiver Riddle return success(); 225ace01605SRiver Riddle } 226ace01605SRiver Riddle return failure(); 227ace01605SRiver Riddle } 228ace01605SRiver Riddle }; 229ace01605SRiver Riddle 230ace01605SRiver Riddle /// cf.cond_br %cond, ^bb1, ^bb2 231ace01605SRiver Riddle /// ^bb1 232ace01605SRiver Riddle /// br ^bbN(...) 233ace01605SRiver Riddle /// ^bb2 234ace01605SRiver Riddle /// br ^bbK(...) 235ace01605SRiver Riddle /// 236ace01605SRiver Riddle /// -> cf.cond_br %cond, ^bbN(...), ^bbK(...) 237ace01605SRiver Riddle /// 238ace01605SRiver Riddle struct SimplifyPassThroughCondBranch : public OpRewritePattern<CondBranchOp> { 239ace01605SRiver Riddle using OpRewritePattern<CondBranchOp>::OpRewritePattern; 240ace01605SRiver Riddle 241ace01605SRiver Riddle LogicalResult matchAndRewrite(CondBranchOp condbr, 242ace01605SRiver Riddle PatternRewriter &rewriter) const override { 243ace01605SRiver Riddle Block *trueDest = condbr.getTrueDest(), *falseDest = condbr.getFalseDest(); 244ace01605SRiver Riddle ValueRange trueDestOperands = condbr.getTrueOperands(); 245ace01605SRiver Riddle ValueRange falseDestOperands = condbr.getFalseOperands(); 246ace01605SRiver Riddle SmallVector<Value, 4> trueDestOperandStorage, falseDestOperandStorage; 247ace01605SRiver Riddle 248ace01605SRiver Riddle // Try to collapse one of the current successors. 249ace01605SRiver Riddle LogicalResult collapsedTrue = 250ace01605SRiver Riddle collapseBranch(trueDest, trueDestOperands, trueDestOperandStorage); 251ace01605SRiver Riddle LogicalResult collapsedFalse = 252ace01605SRiver Riddle collapseBranch(falseDest, falseDestOperands, falseDestOperandStorage); 253ace01605SRiver Riddle if (failed(collapsedTrue) && failed(collapsedFalse)) 254ace01605SRiver Riddle return failure(); 255ace01605SRiver Riddle 256ace01605SRiver Riddle // Create a new branch with the collapsed successors. 257ace01605SRiver Riddle rewriter.replaceOpWithNewOp<CondBranchOp>(condbr, condbr.getCondition(), 258ace01605SRiver Riddle trueDest, trueDestOperands, 259ace01605SRiver Riddle falseDest, falseDestOperands); 260ace01605SRiver Riddle return success(); 261ace01605SRiver Riddle } 262ace01605SRiver Riddle }; 263ace01605SRiver Riddle 264ace01605SRiver Riddle /// cf.cond_br %cond, ^bb1(A, ..., N), ^bb1(A, ..., N) 265ace01605SRiver Riddle /// -> br ^bb1(A, ..., N) 266ace01605SRiver Riddle /// 267ace01605SRiver Riddle /// cf.cond_br %cond, ^bb1(A), ^bb1(B) 268ace01605SRiver Riddle /// -> %select = arith.select %cond, A, B 269ace01605SRiver Riddle /// br ^bb1(%select) 270ace01605SRiver Riddle /// 271ace01605SRiver Riddle struct SimplifyCondBranchIdenticalSuccessors 272ace01605SRiver Riddle : public OpRewritePattern<CondBranchOp> { 273ace01605SRiver Riddle using OpRewritePattern<CondBranchOp>::OpRewritePattern; 274ace01605SRiver Riddle 275ace01605SRiver Riddle LogicalResult matchAndRewrite(CondBranchOp condbr, 276ace01605SRiver Riddle PatternRewriter &rewriter) const override { 277ace01605SRiver Riddle // Check that the true and false destinations are the same and have the same 278ace01605SRiver Riddle // operands. 279ace01605SRiver Riddle Block *trueDest = condbr.getTrueDest(); 280ace01605SRiver Riddle if (trueDest != condbr.getFalseDest()) 281ace01605SRiver Riddle return failure(); 282ace01605SRiver Riddle 283ace01605SRiver Riddle // If all of the operands match, no selects need to be generated. 284ace01605SRiver Riddle OperandRange trueOperands = condbr.getTrueOperands(); 285ace01605SRiver Riddle OperandRange falseOperands = condbr.getFalseOperands(); 286ace01605SRiver Riddle if (trueOperands == falseOperands) { 287ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, trueDest, trueOperands); 288ace01605SRiver Riddle return success(); 289ace01605SRiver Riddle } 290ace01605SRiver Riddle 291ace01605SRiver Riddle // Otherwise, if the current block is the only predecessor insert selects 292ace01605SRiver Riddle // for any mismatched branch operands. 293ace01605SRiver Riddle if (trueDest->getUniquePredecessor() != condbr->getBlock()) 294ace01605SRiver Riddle return failure(); 295ace01605SRiver Riddle 296ace01605SRiver Riddle // Generate a select for any operands that differ between the two. 297ace01605SRiver Riddle SmallVector<Value, 8> mergedOperands; 298ace01605SRiver Riddle mergedOperands.reserve(trueOperands.size()); 299ace01605SRiver Riddle Value condition = condbr.getCondition(); 300ace01605SRiver Riddle for (auto it : llvm::zip(trueOperands, falseOperands)) { 301ace01605SRiver Riddle if (std::get<0>(it) == std::get<1>(it)) 302ace01605SRiver Riddle mergedOperands.push_back(std::get<0>(it)); 303ace01605SRiver Riddle else 304ace01605SRiver Riddle mergedOperands.push_back(rewriter.create<arith::SelectOp>( 305ace01605SRiver Riddle condbr.getLoc(), condition, std::get<0>(it), std::get<1>(it))); 306ace01605SRiver Riddle } 307ace01605SRiver Riddle 308ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, trueDest, mergedOperands); 309ace01605SRiver Riddle return success(); 310ace01605SRiver Riddle } 311ace01605SRiver Riddle }; 312ace01605SRiver Riddle 313ace01605SRiver Riddle /// ... 314ace01605SRiver Riddle /// cf.cond_br %cond, ^bb1(...), ^bb2(...) 315ace01605SRiver Riddle /// ... 316ace01605SRiver Riddle /// ^bb1: // has single predecessor 317ace01605SRiver Riddle /// ... 318ace01605SRiver Riddle /// cf.cond_br %cond, ^bb3(...), ^bb4(...) 319ace01605SRiver Riddle /// 320ace01605SRiver Riddle /// -> 321ace01605SRiver Riddle /// 322ace01605SRiver Riddle /// ... 323ace01605SRiver Riddle /// cf.cond_br %cond, ^bb1(...), ^bb2(...) 324ace01605SRiver Riddle /// ... 325ace01605SRiver Riddle /// ^bb1: // has single predecessor 326ace01605SRiver Riddle /// ... 327ace01605SRiver Riddle /// br ^bb3(...) 328ace01605SRiver Riddle /// 329ace01605SRiver Riddle struct SimplifyCondBranchFromCondBranchOnSameCondition 330ace01605SRiver Riddle : public OpRewritePattern<CondBranchOp> { 331ace01605SRiver Riddle using OpRewritePattern<CondBranchOp>::OpRewritePattern; 332ace01605SRiver Riddle 333ace01605SRiver Riddle LogicalResult matchAndRewrite(CondBranchOp condbr, 334ace01605SRiver Riddle PatternRewriter &rewriter) const override { 335ace01605SRiver Riddle // Check that we have a single distinct predecessor. 336ace01605SRiver Riddle Block *currentBlock = condbr->getBlock(); 337ace01605SRiver Riddle Block *predecessor = currentBlock->getSinglePredecessor(); 338ace01605SRiver Riddle if (!predecessor) 339ace01605SRiver Riddle return failure(); 340ace01605SRiver Riddle 341ace01605SRiver Riddle // Check that the predecessor terminates with a conditional branch to this 342ace01605SRiver Riddle // block and that it branches on the same condition. 343ace01605SRiver Riddle auto predBranch = dyn_cast<CondBranchOp>(predecessor->getTerminator()); 344ace01605SRiver Riddle if (!predBranch || condbr.getCondition() != predBranch.getCondition()) 345ace01605SRiver Riddle return failure(); 346ace01605SRiver Riddle 347ace01605SRiver Riddle // Fold this branch to an unconditional branch. 348ace01605SRiver Riddle if (currentBlock == predBranch.getTrueDest()) 349ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, condbr.getTrueDest(), 350ace01605SRiver Riddle condbr.getTrueDestOperands()); 351ace01605SRiver Riddle else 352ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(condbr, condbr.getFalseDest(), 353ace01605SRiver Riddle condbr.getFalseDestOperands()); 354ace01605SRiver Riddle return success(); 355ace01605SRiver Riddle } 356ace01605SRiver Riddle }; 357ace01605SRiver Riddle 358ace01605SRiver Riddle /// cf.cond_br %arg0, ^trueB, ^falseB 359ace01605SRiver Riddle /// 360ace01605SRiver Riddle /// ^trueB: 361ace01605SRiver Riddle /// "test.consumer1"(%arg0) : (i1) -> () 362ace01605SRiver Riddle /// ... 363ace01605SRiver Riddle /// 364ace01605SRiver Riddle /// ^falseB: 365ace01605SRiver Riddle /// "test.consumer2"(%arg0) : (i1) -> () 366ace01605SRiver Riddle /// ... 367ace01605SRiver Riddle /// 368ace01605SRiver Riddle /// -> 369ace01605SRiver Riddle /// 370ace01605SRiver Riddle /// cf.cond_br %arg0, ^trueB, ^falseB 371ace01605SRiver Riddle /// ^trueB: 372ace01605SRiver Riddle /// "test.consumer1"(%true) : (i1) -> () 373ace01605SRiver Riddle /// ... 374ace01605SRiver Riddle /// 375ace01605SRiver Riddle /// ^falseB: 376ace01605SRiver Riddle /// "test.consumer2"(%false) : (i1) -> () 377ace01605SRiver Riddle /// ... 378ace01605SRiver Riddle struct CondBranchTruthPropagation : public OpRewritePattern<CondBranchOp> { 379ace01605SRiver Riddle using OpRewritePattern<CondBranchOp>::OpRewritePattern; 380ace01605SRiver Riddle 381ace01605SRiver Riddle LogicalResult matchAndRewrite(CondBranchOp condbr, 382ace01605SRiver Riddle PatternRewriter &rewriter) const override { 383ace01605SRiver Riddle // Check that we have a single distinct predecessor. 384ace01605SRiver Riddle bool replaced = false; 385ace01605SRiver Riddle Type ty = rewriter.getI1Type(); 386ace01605SRiver Riddle 387ace01605SRiver Riddle // These variables serve to prevent creating duplicate constants 388ace01605SRiver Riddle // and hold constant true or false values. 389ace01605SRiver Riddle Value constantTrue = nullptr; 390ace01605SRiver Riddle Value constantFalse = nullptr; 391ace01605SRiver Riddle 392ace01605SRiver Riddle // TODO These checks can be expanded to encompas any use with only 393ace01605SRiver Riddle // either the true of false edge as a predecessor. For now, we fall 394ace01605SRiver Riddle // back to checking the single predecessor is given by the true/fasle 395ace01605SRiver Riddle // destination, thereby ensuring that only that edge can reach the 396ace01605SRiver Riddle // op. 397ace01605SRiver Riddle if (condbr.getTrueDest()->getSinglePredecessor()) { 398ace01605SRiver Riddle for (OpOperand &use : 399ace01605SRiver Riddle llvm::make_early_inc_range(condbr.getCondition().getUses())) { 400ace01605SRiver Riddle if (use.getOwner()->getBlock() == condbr.getTrueDest()) { 401ace01605SRiver Riddle replaced = true; 402ace01605SRiver Riddle 403ace01605SRiver Riddle if (!constantTrue) 404ace01605SRiver Riddle constantTrue = rewriter.create<arith::ConstantOp>( 405ace01605SRiver Riddle condbr.getLoc(), ty, rewriter.getBoolAttr(true)); 406ace01605SRiver Riddle 407ace01605SRiver Riddle rewriter.updateRootInPlace(use.getOwner(), 408ace01605SRiver Riddle [&] { use.set(constantTrue); }); 409ace01605SRiver Riddle } 410ace01605SRiver Riddle } 411ace01605SRiver Riddle } 412ace01605SRiver Riddle if (condbr.getFalseDest()->getSinglePredecessor()) { 413ace01605SRiver Riddle for (OpOperand &use : 414ace01605SRiver Riddle llvm::make_early_inc_range(condbr.getCondition().getUses())) { 415ace01605SRiver Riddle if (use.getOwner()->getBlock() == condbr.getFalseDest()) { 416ace01605SRiver Riddle replaced = true; 417ace01605SRiver Riddle 418ace01605SRiver Riddle if (!constantFalse) 419ace01605SRiver Riddle constantFalse = rewriter.create<arith::ConstantOp>( 420ace01605SRiver Riddle condbr.getLoc(), ty, rewriter.getBoolAttr(false)); 421ace01605SRiver Riddle 422ace01605SRiver Riddle rewriter.updateRootInPlace(use.getOwner(), 423ace01605SRiver Riddle [&] { use.set(constantFalse); }); 424ace01605SRiver Riddle } 425ace01605SRiver Riddle } 426ace01605SRiver Riddle } 427ace01605SRiver Riddle return success(replaced); 428ace01605SRiver Riddle } 429ace01605SRiver Riddle }; 430ace01605SRiver Riddle } // namespace 431ace01605SRiver Riddle 432ace01605SRiver Riddle void CondBranchOp::getCanonicalizationPatterns(RewritePatternSet &results, 433ace01605SRiver Riddle MLIRContext *context) { 434ace01605SRiver Riddle results.add<SimplifyConstCondBranchPred, SimplifyPassThroughCondBranch, 435ace01605SRiver Riddle SimplifyCondBranchIdenticalSuccessors, 436ace01605SRiver Riddle SimplifyCondBranchFromCondBranchOnSameCondition, 437ace01605SRiver Riddle CondBranchTruthPropagation>(context); 438ace01605SRiver Riddle } 439ace01605SRiver Riddle 440ace01605SRiver Riddle Optional<MutableOperandRange> 441ace01605SRiver Riddle CondBranchOp::getMutableSuccessorOperands(unsigned index) { 442ace01605SRiver Riddle assert(index < getNumSuccessors() && "invalid successor index"); 443ace01605SRiver Riddle return index == trueIndex ? getTrueDestOperandsMutable() 444ace01605SRiver Riddle : getFalseDestOperandsMutable(); 445ace01605SRiver Riddle } 446ace01605SRiver Riddle 447ace01605SRiver Riddle Block *CondBranchOp::getSuccessorForOperands(ArrayRef<Attribute> operands) { 448ace01605SRiver Riddle if (IntegerAttr condAttr = operands.front().dyn_cast_or_null<IntegerAttr>()) 449ace01605SRiver Riddle return condAttr.getValue().isOneValue() ? getTrueDest() : getFalseDest(); 450ace01605SRiver Riddle return nullptr; 451ace01605SRiver Riddle } 452ace01605SRiver Riddle 453ace01605SRiver Riddle //===----------------------------------------------------------------------===// 454ace01605SRiver Riddle // SwitchOp 455ace01605SRiver Riddle //===----------------------------------------------------------------------===// 456ace01605SRiver Riddle 457ace01605SRiver Riddle void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value, 458ace01605SRiver Riddle Block *defaultDestination, ValueRange defaultOperands, 459ace01605SRiver Riddle DenseIntElementsAttr caseValues, 460ace01605SRiver Riddle BlockRange caseDestinations, 461ace01605SRiver Riddle ArrayRef<ValueRange> caseOperands) { 462ace01605SRiver Riddle build(builder, result, value, defaultOperands, caseOperands, caseValues, 463ace01605SRiver Riddle defaultDestination, caseDestinations); 464ace01605SRiver Riddle } 465ace01605SRiver Riddle 466ace01605SRiver Riddle void SwitchOp::build(OpBuilder &builder, OperationState &result, Value value, 467ace01605SRiver Riddle Block *defaultDestination, ValueRange defaultOperands, 468ace01605SRiver Riddle ArrayRef<APInt> caseValues, BlockRange caseDestinations, 469ace01605SRiver Riddle ArrayRef<ValueRange> caseOperands) { 470ace01605SRiver Riddle DenseIntElementsAttr caseValuesAttr; 471ace01605SRiver Riddle if (!caseValues.empty()) { 472ace01605SRiver Riddle ShapedType caseValueType = VectorType::get( 473ace01605SRiver Riddle static_cast<int64_t>(caseValues.size()), value.getType()); 474ace01605SRiver Riddle caseValuesAttr = DenseIntElementsAttr::get(caseValueType, caseValues); 475ace01605SRiver Riddle } 476ace01605SRiver Riddle build(builder, result, value, defaultDestination, defaultOperands, 477ace01605SRiver Riddle caseValuesAttr, caseDestinations, caseOperands); 478ace01605SRiver Riddle } 479ace01605SRiver Riddle 480ace01605SRiver Riddle /// <cases> ::= `default` `:` bb-id (`(` ssa-use-and-type-list `)`)? 481ace01605SRiver Riddle /// ( `,` integer `:` bb-id (`(` ssa-use-and-type-list `)`)? )* 482ace01605SRiver Riddle static ParseResult parseSwitchOpCases( 483ace01605SRiver Riddle OpAsmParser &parser, Type &flagType, Block *&defaultDestination, 484*e13d23bcSMarkus Böck SmallVectorImpl<OpAsmParser::UnresolvedOperand> &defaultOperands, 485ace01605SRiver Riddle SmallVectorImpl<Type> &defaultOperandTypes, 486ace01605SRiver Riddle DenseIntElementsAttr &caseValues, 487ace01605SRiver Riddle SmallVectorImpl<Block *> &caseDestinations, 488*e13d23bcSMarkus Böck SmallVectorImpl<SmallVector<OpAsmParser::UnresolvedOperand>> &caseOperands, 489ace01605SRiver Riddle SmallVectorImpl<SmallVector<Type>> &caseOperandTypes) { 490ace01605SRiver Riddle if (parser.parseKeyword("default") || parser.parseColon() || 491ace01605SRiver Riddle parser.parseSuccessor(defaultDestination)) 492ace01605SRiver Riddle return failure(); 493ace01605SRiver Riddle if (succeeded(parser.parseOptionalLParen())) { 494ace01605SRiver Riddle if (parser.parseRegionArgumentList(defaultOperands) || 495ace01605SRiver Riddle parser.parseColonTypeList(defaultOperandTypes) || parser.parseRParen()) 496ace01605SRiver Riddle return failure(); 497ace01605SRiver Riddle } 498ace01605SRiver Riddle 499ace01605SRiver Riddle SmallVector<APInt> values; 500ace01605SRiver Riddle unsigned bitWidth = flagType.getIntOrFloatBitWidth(); 501ace01605SRiver Riddle while (succeeded(parser.parseOptionalComma())) { 502ace01605SRiver Riddle int64_t value = 0; 503ace01605SRiver Riddle if (failed(parser.parseInteger(value))) 504ace01605SRiver Riddle return failure(); 505ace01605SRiver Riddle values.push_back(APInt(bitWidth, value)); 506ace01605SRiver Riddle 507ace01605SRiver Riddle Block *destination; 508*e13d23bcSMarkus Böck SmallVector<OpAsmParser::UnresolvedOperand> operands; 509ace01605SRiver Riddle SmallVector<Type> operandTypes; 510ace01605SRiver Riddle if (failed(parser.parseColon()) || 511ace01605SRiver Riddle failed(parser.parseSuccessor(destination))) 512ace01605SRiver Riddle return failure(); 513ace01605SRiver Riddle if (succeeded(parser.parseOptionalLParen())) { 514ace01605SRiver Riddle if (failed(parser.parseRegionArgumentList(operands)) || 515ace01605SRiver Riddle failed(parser.parseColonTypeList(operandTypes)) || 516ace01605SRiver Riddle failed(parser.parseRParen())) 517ace01605SRiver Riddle return failure(); 518ace01605SRiver Riddle } 519ace01605SRiver Riddle caseDestinations.push_back(destination); 520ace01605SRiver Riddle caseOperands.emplace_back(operands); 521ace01605SRiver Riddle caseOperandTypes.emplace_back(operandTypes); 522ace01605SRiver Riddle } 523ace01605SRiver Riddle 524ace01605SRiver Riddle if (!values.empty()) { 525ace01605SRiver Riddle ShapedType caseValueType = 526ace01605SRiver Riddle VectorType::get(static_cast<int64_t>(values.size()), flagType); 527ace01605SRiver Riddle caseValues = DenseIntElementsAttr::get(caseValueType, values); 528ace01605SRiver Riddle } 529ace01605SRiver Riddle return success(); 530ace01605SRiver Riddle } 531ace01605SRiver Riddle 532ace01605SRiver Riddle static void printSwitchOpCases( 533ace01605SRiver Riddle OpAsmPrinter &p, SwitchOp op, Type flagType, Block *defaultDestination, 534ace01605SRiver Riddle OperandRange defaultOperands, TypeRange defaultOperandTypes, 535ace01605SRiver Riddle DenseIntElementsAttr caseValues, SuccessorRange caseDestinations, 536ace01605SRiver Riddle OperandRangeRange caseOperands, const TypeRangeRange &caseOperandTypes) { 537ace01605SRiver Riddle p << " default: "; 538ace01605SRiver Riddle p.printSuccessorAndUseList(defaultDestination, defaultOperands); 539ace01605SRiver Riddle 540ace01605SRiver Riddle if (!caseValues) 541ace01605SRiver Riddle return; 542ace01605SRiver Riddle 543ace01605SRiver Riddle for (const auto &it : llvm::enumerate(caseValues.getValues<APInt>())) { 544ace01605SRiver Riddle p << ','; 545ace01605SRiver Riddle p.printNewline(); 546ace01605SRiver Riddle p << " "; 547ace01605SRiver Riddle p << it.value().getLimitedValue(); 548ace01605SRiver Riddle p << ": "; 549ace01605SRiver Riddle p.printSuccessorAndUseList(caseDestinations[it.index()], 550ace01605SRiver Riddle caseOperands[it.index()]); 551ace01605SRiver Riddle } 552ace01605SRiver Riddle p.printNewline(); 553ace01605SRiver Riddle } 554ace01605SRiver Riddle 555ace01605SRiver Riddle LogicalResult SwitchOp::verify() { 556ace01605SRiver Riddle auto caseValues = getCaseValues(); 557ace01605SRiver Riddle auto caseDestinations = getCaseDestinations(); 558ace01605SRiver Riddle 559ace01605SRiver Riddle if (!caseValues && caseDestinations.empty()) 560ace01605SRiver Riddle return success(); 561ace01605SRiver Riddle 562ace01605SRiver Riddle Type flagType = getFlag().getType(); 563ace01605SRiver Riddle Type caseValueType = caseValues->getType().getElementType(); 564ace01605SRiver Riddle if (caseValueType != flagType) 565ace01605SRiver Riddle return emitOpError() << "'flag' type (" << flagType 566ace01605SRiver Riddle << ") should match case value type (" << caseValueType 567ace01605SRiver Riddle << ")"; 568ace01605SRiver Riddle 569ace01605SRiver Riddle if (caseValues && 570ace01605SRiver Riddle caseValues->size() != static_cast<int64_t>(caseDestinations.size())) 571ace01605SRiver Riddle return emitOpError() << "number of case values (" << caseValues->size() 572ace01605SRiver Riddle << ") should match number of " 573ace01605SRiver Riddle "case destinations (" 574ace01605SRiver Riddle << caseDestinations.size() << ")"; 575ace01605SRiver Riddle return success(); 576ace01605SRiver Riddle } 577ace01605SRiver Riddle 578ace01605SRiver Riddle Optional<MutableOperandRange> 579ace01605SRiver Riddle SwitchOp::getMutableSuccessorOperands(unsigned index) { 580ace01605SRiver Riddle assert(index < getNumSuccessors() && "invalid successor index"); 581ace01605SRiver Riddle return index == 0 ? getDefaultOperandsMutable() 582ace01605SRiver Riddle : getCaseOperandsMutable(index - 1); 583ace01605SRiver Riddle } 584ace01605SRiver Riddle 585ace01605SRiver Riddle Block *SwitchOp::getSuccessorForOperands(ArrayRef<Attribute> operands) { 586ace01605SRiver Riddle Optional<DenseIntElementsAttr> caseValues = getCaseValues(); 587ace01605SRiver Riddle 588ace01605SRiver Riddle if (!caseValues) 589ace01605SRiver Riddle return getDefaultDestination(); 590ace01605SRiver Riddle 591ace01605SRiver Riddle SuccessorRange caseDests = getCaseDestinations(); 592ace01605SRiver Riddle if (auto value = operands.front().dyn_cast_or_null<IntegerAttr>()) { 593ace01605SRiver Riddle for (const auto &it : llvm::enumerate(caseValues->getValues<APInt>())) 594ace01605SRiver Riddle if (it.value() == value.getValue()) 595ace01605SRiver Riddle return caseDests[it.index()]; 596ace01605SRiver Riddle return getDefaultDestination(); 597ace01605SRiver Riddle } 598ace01605SRiver Riddle return nullptr; 599ace01605SRiver Riddle } 600ace01605SRiver Riddle 601ace01605SRiver Riddle /// switch %flag : i32, [ 602ace01605SRiver Riddle /// default: ^bb1 603ace01605SRiver Riddle /// ] 604ace01605SRiver Riddle /// -> br ^bb1 605ace01605SRiver Riddle static LogicalResult simplifySwitchWithOnlyDefault(SwitchOp op, 606ace01605SRiver Riddle PatternRewriter &rewriter) { 607ace01605SRiver Riddle if (!op.getCaseDestinations().empty()) 608ace01605SRiver Riddle return failure(); 609ace01605SRiver Riddle 610ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(op, op.getDefaultDestination(), 611ace01605SRiver Riddle op.getDefaultOperands()); 612ace01605SRiver Riddle return success(); 613ace01605SRiver Riddle } 614ace01605SRiver Riddle 615ace01605SRiver Riddle /// switch %flag : i32, [ 616ace01605SRiver Riddle /// default: ^bb1, 617ace01605SRiver Riddle /// 42: ^bb1, 618ace01605SRiver Riddle /// 43: ^bb2 619ace01605SRiver Riddle /// ] 620ace01605SRiver Riddle /// -> 621ace01605SRiver Riddle /// switch %flag : i32, [ 622ace01605SRiver Riddle /// default: ^bb1, 623ace01605SRiver Riddle /// 43: ^bb2 624ace01605SRiver Riddle /// ] 625ace01605SRiver Riddle static LogicalResult 626ace01605SRiver Riddle dropSwitchCasesThatMatchDefault(SwitchOp op, PatternRewriter &rewriter) { 627ace01605SRiver Riddle SmallVector<Block *> newCaseDestinations; 628ace01605SRiver Riddle SmallVector<ValueRange> newCaseOperands; 629ace01605SRiver Riddle SmallVector<APInt> newCaseValues; 630ace01605SRiver Riddle bool requiresChange = false; 631ace01605SRiver Riddle auto caseValues = op.getCaseValues(); 632ace01605SRiver Riddle auto caseDests = op.getCaseDestinations(); 633ace01605SRiver Riddle 634ace01605SRiver Riddle for (const auto &it : llvm::enumerate(caseValues->getValues<APInt>())) { 635ace01605SRiver Riddle if (caseDests[it.index()] == op.getDefaultDestination() && 636ace01605SRiver Riddle op.getCaseOperands(it.index()) == op.getDefaultOperands()) { 637ace01605SRiver Riddle requiresChange = true; 638ace01605SRiver Riddle continue; 639ace01605SRiver Riddle } 640ace01605SRiver Riddle newCaseDestinations.push_back(caseDests[it.index()]); 641ace01605SRiver Riddle newCaseOperands.push_back(op.getCaseOperands(it.index())); 642ace01605SRiver Riddle newCaseValues.push_back(it.value()); 643ace01605SRiver Riddle } 644ace01605SRiver Riddle 645ace01605SRiver Riddle if (!requiresChange) 646ace01605SRiver Riddle return failure(); 647ace01605SRiver Riddle 648ace01605SRiver Riddle rewriter.replaceOpWithNewOp<SwitchOp>( 649ace01605SRiver Riddle op, op.getFlag(), op.getDefaultDestination(), op.getDefaultOperands(), 650ace01605SRiver Riddle newCaseValues, newCaseDestinations, newCaseOperands); 651ace01605SRiver Riddle return success(); 652ace01605SRiver Riddle } 653ace01605SRiver Riddle 654ace01605SRiver Riddle /// Helper for folding a switch with a constant value. 655ace01605SRiver Riddle /// switch %c_42 : i32, [ 656ace01605SRiver Riddle /// default: ^bb1 , 657ace01605SRiver Riddle /// 42: ^bb2, 658ace01605SRiver Riddle /// 43: ^bb3 659ace01605SRiver Riddle /// ] 660ace01605SRiver Riddle /// -> br ^bb2 661ace01605SRiver Riddle static void foldSwitch(SwitchOp op, PatternRewriter &rewriter, 662ace01605SRiver Riddle const APInt &caseValue) { 663ace01605SRiver Riddle auto caseValues = op.getCaseValues(); 664ace01605SRiver Riddle for (const auto &it : llvm::enumerate(caseValues->getValues<APInt>())) { 665ace01605SRiver Riddle if (it.value() == caseValue) { 666ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>( 667ace01605SRiver Riddle op, op.getCaseDestinations()[it.index()], 668ace01605SRiver Riddle op.getCaseOperands(it.index())); 669ace01605SRiver Riddle return; 670ace01605SRiver Riddle } 671ace01605SRiver Riddle } 672ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(op, op.getDefaultDestination(), 673ace01605SRiver Riddle op.getDefaultOperands()); 674ace01605SRiver Riddle } 675ace01605SRiver Riddle 676ace01605SRiver Riddle /// switch %c_42 : i32, [ 677ace01605SRiver Riddle /// default: ^bb1, 678ace01605SRiver Riddle /// 42: ^bb2, 679ace01605SRiver Riddle /// 43: ^bb3 680ace01605SRiver Riddle /// ] 681ace01605SRiver Riddle /// -> br ^bb2 682ace01605SRiver Riddle static LogicalResult simplifyConstSwitchValue(SwitchOp op, 683ace01605SRiver Riddle PatternRewriter &rewriter) { 684ace01605SRiver Riddle APInt caseValue; 685ace01605SRiver Riddle if (!matchPattern(op.getFlag(), m_ConstantInt(&caseValue))) 686ace01605SRiver Riddle return failure(); 687ace01605SRiver Riddle 688ace01605SRiver Riddle foldSwitch(op, rewriter, caseValue); 689ace01605SRiver Riddle return success(); 690ace01605SRiver Riddle } 691ace01605SRiver Riddle 692ace01605SRiver Riddle /// switch %c_42 : i32, [ 693ace01605SRiver Riddle /// default: ^bb1, 694ace01605SRiver Riddle /// 42: ^bb2, 695ace01605SRiver Riddle /// ] 696ace01605SRiver Riddle /// ^bb2: 697ace01605SRiver Riddle /// br ^bb3 698ace01605SRiver Riddle /// -> 699ace01605SRiver Riddle /// switch %c_42 : i32, [ 700ace01605SRiver Riddle /// default: ^bb1, 701ace01605SRiver Riddle /// 42: ^bb3, 702ace01605SRiver Riddle /// ] 703ace01605SRiver Riddle static LogicalResult simplifyPassThroughSwitch(SwitchOp op, 704ace01605SRiver Riddle PatternRewriter &rewriter) { 705ace01605SRiver Riddle SmallVector<Block *> newCaseDests; 706ace01605SRiver Riddle SmallVector<ValueRange> newCaseOperands; 707ace01605SRiver Riddle SmallVector<SmallVector<Value>> argStorage; 708ace01605SRiver Riddle auto caseValues = op.getCaseValues(); 709ace01605SRiver Riddle auto caseDests = op.getCaseDestinations(); 710ace01605SRiver Riddle bool requiresChange = false; 711ace01605SRiver Riddle for (int64_t i = 0, size = caseValues->size(); i < size; ++i) { 712ace01605SRiver Riddle Block *caseDest = caseDests[i]; 713ace01605SRiver Riddle ValueRange caseOperands = op.getCaseOperands(i); 714ace01605SRiver Riddle argStorage.emplace_back(); 715ace01605SRiver Riddle if (succeeded(collapseBranch(caseDest, caseOperands, argStorage.back()))) 716ace01605SRiver Riddle requiresChange = true; 717ace01605SRiver Riddle 718ace01605SRiver Riddle newCaseDests.push_back(caseDest); 719ace01605SRiver Riddle newCaseOperands.push_back(caseOperands); 720ace01605SRiver Riddle } 721ace01605SRiver Riddle 722ace01605SRiver Riddle Block *defaultDest = op.getDefaultDestination(); 723ace01605SRiver Riddle ValueRange defaultOperands = op.getDefaultOperands(); 724ace01605SRiver Riddle argStorage.emplace_back(); 725ace01605SRiver Riddle 726ace01605SRiver Riddle if (succeeded( 727ace01605SRiver Riddle collapseBranch(defaultDest, defaultOperands, argStorage.back()))) 728ace01605SRiver Riddle requiresChange = true; 729ace01605SRiver Riddle 730ace01605SRiver Riddle if (!requiresChange) 731ace01605SRiver Riddle return failure(); 732ace01605SRiver Riddle 733ace01605SRiver Riddle rewriter.replaceOpWithNewOp<SwitchOp>(op, op.getFlag(), defaultDest, 734ace01605SRiver Riddle defaultOperands, caseValues.getValue(), 735ace01605SRiver Riddle newCaseDests, newCaseOperands); 736ace01605SRiver Riddle return success(); 737ace01605SRiver Riddle } 738ace01605SRiver Riddle 739ace01605SRiver Riddle /// switch %flag : i32, [ 740ace01605SRiver Riddle /// default: ^bb1, 741ace01605SRiver Riddle /// 42: ^bb2, 742ace01605SRiver Riddle /// ] 743ace01605SRiver Riddle /// ^bb2: 744ace01605SRiver Riddle /// switch %flag : i32, [ 745ace01605SRiver Riddle /// default: ^bb3, 746ace01605SRiver Riddle /// 42: ^bb4 747ace01605SRiver Riddle /// ] 748ace01605SRiver Riddle /// -> 749ace01605SRiver Riddle /// switch %flag : i32, [ 750ace01605SRiver Riddle /// default: ^bb1, 751ace01605SRiver Riddle /// 42: ^bb2, 752ace01605SRiver Riddle /// ] 753ace01605SRiver Riddle /// ^bb2: 754ace01605SRiver Riddle /// br ^bb4 755ace01605SRiver Riddle /// 756ace01605SRiver Riddle /// and 757ace01605SRiver Riddle /// 758ace01605SRiver Riddle /// switch %flag : i32, [ 759ace01605SRiver Riddle /// default: ^bb1, 760ace01605SRiver Riddle /// 42: ^bb2, 761ace01605SRiver Riddle /// ] 762ace01605SRiver Riddle /// ^bb2: 763ace01605SRiver Riddle /// switch %flag : i32, [ 764ace01605SRiver Riddle /// default: ^bb3, 765ace01605SRiver Riddle /// 43: ^bb4 766ace01605SRiver Riddle /// ] 767ace01605SRiver Riddle /// -> 768ace01605SRiver Riddle /// switch %flag : i32, [ 769ace01605SRiver Riddle /// default: ^bb1, 770ace01605SRiver Riddle /// 42: ^bb2, 771ace01605SRiver Riddle /// ] 772ace01605SRiver Riddle /// ^bb2: 773ace01605SRiver Riddle /// br ^bb3 774ace01605SRiver Riddle static LogicalResult 775ace01605SRiver Riddle simplifySwitchFromSwitchOnSameCondition(SwitchOp op, 776ace01605SRiver Riddle PatternRewriter &rewriter) { 777ace01605SRiver Riddle // Check that we have a single distinct predecessor. 778ace01605SRiver Riddle Block *currentBlock = op->getBlock(); 779ace01605SRiver Riddle Block *predecessor = currentBlock->getSinglePredecessor(); 780ace01605SRiver Riddle if (!predecessor) 781ace01605SRiver Riddle return failure(); 782ace01605SRiver Riddle 783ace01605SRiver Riddle // Check that the predecessor terminates with a switch branch to this block 784ace01605SRiver Riddle // and that it branches on the same condition and that this branch isn't the 785ace01605SRiver Riddle // default destination. 786ace01605SRiver Riddle auto predSwitch = dyn_cast<SwitchOp>(predecessor->getTerminator()); 787ace01605SRiver Riddle if (!predSwitch || op.getFlag() != predSwitch.getFlag() || 788ace01605SRiver Riddle predSwitch.getDefaultDestination() == currentBlock) 789ace01605SRiver Riddle return failure(); 790ace01605SRiver Riddle 791ace01605SRiver Riddle // Fold this switch to an unconditional branch. 792ace01605SRiver Riddle SuccessorRange predDests = predSwitch.getCaseDestinations(); 793ace01605SRiver Riddle auto it = llvm::find(predDests, currentBlock); 794ace01605SRiver Riddle if (it != predDests.end()) { 795ace01605SRiver Riddle Optional<DenseIntElementsAttr> predCaseValues = predSwitch.getCaseValues(); 796ace01605SRiver Riddle foldSwitch(op, rewriter, 797ace01605SRiver Riddle predCaseValues->getValues<APInt>()[it - predDests.begin()]); 798ace01605SRiver Riddle } else { 799ace01605SRiver Riddle rewriter.replaceOpWithNewOp<BranchOp>(op, op.getDefaultDestination(), 800ace01605SRiver Riddle op.getDefaultOperands()); 801ace01605SRiver Riddle } 802ace01605SRiver Riddle return success(); 803ace01605SRiver Riddle } 804ace01605SRiver Riddle 805ace01605SRiver Riddle /// switch %flag : i32, [ 806ace01605SRiver Riddle /// default: ^bb1, 807ace01605SRiver Riddle /// 42: ^bb2 808ace01605SRiver Riddle /// ] 809ace01605SRiver Riddle /// ^bb1: 810ace01605SRiver Riddle /// switch %flag : i32, [ 811ace01605SRiver Riddle /// default: ^bb3, 812ace01605SRiver Riddle /// 42: ^bb4, 813ace01605SRiver Riddle /// 43: ^bb5 814ace01605SRiver Riddle /// ] 815ace01605SRiver Riddle /// -> 816ace01605SRiver Riddle /// switch %flag : i32, [ 817ace01605SRiver Riddle /// default: ^bb1, 818ace01605SRiver Riddle /// 42: ^bb2, 819ace01605SRiver Riddle /// ] 820ace01605SRiver Riddle /// ^bb1: 821ace01605SRiver Riddle /// switch %flag : i32, [ 822ace01605SRiver Riddle /// default: ^bb3, 823ace01605SRiver Riddle /// 43: ^bb5 824ace01605SRiver Riddle /// ] 825ace01605SRiver Riddle static LogicalResult 826ace01605SRiver Riddle simplifySwitchFromDefaultSwitchOnSameCondition(SwitchOp op, 827ace01605SRiver Riddle PatternRewriter &rewriter) { 828ace01605SRiver Riddle // Check that we have a single distinct predecessor. 829ace01605SRiver Riddle Block *currentBlock = op->getBlock(); 830ace01605SRiver Riddle Block *predecessor = currentBlock->getSinglePredecessor(); 831ace01605SRiver Riddle if (!predecessor) 832ace01605SRiver Riddle return failure(); 833ace01605SRiver Riddle 834ace01605SRiver Riddle // Check that the predecessor terminates with a switch branch to this block 835ace01605SRiver Riddle // and that it branches on the same condition and that this branch is the 836ace01605SRiver Riddle // default destination. 837ace01605SRiver Riddle auto predSwitch = dyn_cast<SwitchOp>(predecessor->getTerminator()); 838ace01605SRiver Riddle if (!predSwitch || op.getFlag() != predSwitch.getFlag() || 839ace01605SRiver Riddle predSwitch.getDefaultDestination() != currentBlock) 840ace01605SRiver Riddle return failure(); 841ace01605SRiver Riddle 842ace01605SRiver Riddle // Delete case values that are not possible here. 843ace01605SRiver Riddle DenseSet<APInt> caseValuesToRemove; 844ace01605SRiver Riddle auto predDests = predSwitch.getCaseDestinations(); 845ace01605SRiver Riddle auto predCaseValues = predSwitch.getCaseValues(); 846ace01605SRiver Riddle for (int64_t i = 0, size = predCaseValues->size(); i < size; ++i) 847ace01605SRiver Riddle if (currentBlock != predDests[i]) 848ace01605SRiver Riddle caseValuesToRemove.insert(predCaseValues->getValues<APInt>()[i]); 849ace01605SRiver Riddle 850ace01605SRiver Riddle SmallVector<Block *> newCaseDestinations; 851ace01605SRiver Riddle SmallVector<ValueRange> newCaseOperands; 852ace01605SRiver Riddle SmallVector<APInt> newCaseValues; 853ace01605SRiver Riddle bool requiresChange = false; 854ace01605SRiver Riddle 855ace01605SRiver Riddle auto caseValues = op.getCaseValues(); 856ace01605SRiver Riddle auto caseDests = op.getCaseDestinations(); 857ace01605SRiver Riddle for (const auto &it : llvm::enumerate(caseValues->getValues<APInt>())) { 858ace01605SRiver Riddle if (caseValuesToRemove.contains(it.value())) { 859ace01605SRiver Riddle requiresChange = true; 860ace01605SRiver Riddle continue; 861ace01605SRiver Riddle } 862ace01605SRiver Riddle newCaseDestinations.push_back(caseDests[it.index()]); 863ace01605SRiver Riddle newCaseOperands.push_back(op.getCaseOperands(it.index())); 864ace01605SRiver Riddle newCaseValues.push_back(it.value()); 865ace01605SRiver Riddle } 866ace01605SRiver Riddle 867ace01605SRiver Riddle if (!requiresChange) 868ace01605SRiver Riddle return failure(); 869ace01605SRiver Riddle 870ace01605SRiver Riddle rewriter.replaceOpWithNewOp<SwitchOp>( 871ace01605SRiver Riddle op, op.getFlag(), op.getDefaultDestination(), op.getDefaultOperands(), 872ace01605SRiver Riddle newCaseValues, newCaseDestinations, newCaseOperands); 873ace01605SRiver Riddle return success(); 874ace01605SRiver Riddle } 875ace01605SRiver Riddle 876ace01605SRiver Riddle void SwitchOp::getCanonicalizationPatterns(RewritePatternSet &results, 877ace01605SRiver Riddle MLIRContext *context) { 878ace01605SRiver Riddle results.add(&simplifySwitchWithOnlyDefault) 879ace01605SRiver Riddle .add(&dropSwitchCasesThatMatchDefault) 880ace01605SRiver Riddle .add(&simplifyConstSwitchValue) 881ace01605SRiver Riddle .add(&simplifyPassThroughSwitch) 882ace01605SRiver Riddle .add(&simplifySwitchFromSwitchOnSameCondition) 883ace01605SRiver Riddle .add(&simplifySwitchFromDefaultSwitchOnSameCondition); 884ace01605SRiver Riddle } 885ace01605SRiver Riddle 886ace01605SRiver Riddle //===----------------------------------------------------------------------===// 887ace01605SRiver Riddle // TableGen'd op method definitions 888ace01605SRiver Riddle //===----------------------------------------------------------------------===// 889ace01605SRiver Riddle 890ace01605SRiver Riddle #define GET_OP_CLASSES 891ace01605SRiver Riddle #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.cpp.inc" 892