brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.7 KiB · 22bc0b3 Raw
665 lines · cpp
1//===- DenseAnalysis.cpp - Dense data-flow analysis -----------------------===//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#include "mlir/Analysis/DataFlow/DenseAnalysis.h"10#include "mlir/Analysis/DataFlow/DeadCodeAnalysis.h"11#include "mlir/Analysis/DataFlowFramework.h"12#include "mlir/IR/Block.h"13#include "mlir/IR/OpDefinition.h"14#include "mlir/IR/Operation.h"15#include "mlir/IR/Region.h"16#include "mlir/Interfaces/CallInterfaces.h"17#include "mlir/Interfaces/ControlFlowInterfaces.h"18#include "mlir/Support/LLVM.h"19#include "llvm/ADT/STLExtras.h"20#include "llvm/Support/DebugLog.h"21#include <cassert>22#include <optional>23 24using namespace mlir;25using namespace mlir::dataflow;26 27#define DEBUG_TYPE "dense-analysis"28 29//===----------------------------------------------------------------------===//30// AbstractDenseForwardDataFlowAnalysis31//===----------------------------------------------------------------------===//32 33void AbstractDenseForwardDataFlowAnalysis::initializeEquivalentLatticeAnchor(34    Operation *top) {35  LDBG() << "initializeEquivalentLatticeAnchor: "36         << OpWithFlags(top, OpPrintingFlags().skipRegions());37  top->walk([&](Operation *op) {38    if (isa<RegionBranchOpInterface, CallOpInterface>(op)) {39      LDBG() << "  Skipping "40             << OpWithFlags(op, OpPrintingFlags().skipRegions())41             << " (region branch or call)";42      return;43    }44    LDBG() << "  Building equivalent lattice anchor for "45           << OpWithFlags(op, OpPrintingFlags().skipRegions());46    buildOperationEquivalentLatticeAnchor(op);47  });48}49 50LogicalResult AbstractDenseForwardDataFlowAnalysis::initialize(Operation *top) {51  LDBG() << "initialize (forward): "52         << OpWithFlags(top, OpPrintingFlags().skipRegions());53  // Visit every operation and block.54  if (failed(processOperation(top))) {55    LDBG() << "  Failed to process top-level operation";56    return failure();57  }58 59  for (Region &region : top->getRegions()) {60    LDBG() << "  Processing region with " << region.getBlocks().size()61           << " blocks";62    for (Block &block : region) {63      LDBG() << "    Processing block with " << block.getOperations().size()64             << " operations";65      visitBlock(&block);66      for (Operation &op : block) {67        LDBG() << "      Initializing operation: "68               << OpWithFlags(&op, OpPrintingFlags().skipRegions());69        if (failed(initialize(&op))) {70          LDBG() << "      Failed to initialize operation";71          return failure();72        }73      }74    }75  }76  LDBG() << "  Forward initialization completed successfully";77  return success();78}79 80LogicalResult AbstractDenseForwardDataFlowAnalysis::visit(ProgramPoint *point) {81  LDBG() << "visit (forward): " << *point;82  if (!point->isBlockStart()) {83    LDBG() << "  Processing operation: "84           << OpWithFlags(point->getPrevOp(), OpPrintingFlags().skipRegions());85    return processOperation(point->getPrevOp());86  }87  LDBG() << "  Visiting block: " << point->getBlock();88  visitBlock(point->getBlock());89  return success();90}91 92void AbstractDenseForwardDataFlowAnalysis::visitCallOperation(93    CallOpInterface call, const AbstractDenseLattice &before,94    AbstractDenseLattice *after) {95  LDBG() << "visitCallOperation (forward): "96         << OpWithFlags(call.getOperation(), OpPrintingFlags().skipRegions());97  LDBG() << "  before state: " << before;98  LDBG() << "  after state: " << *after;99 100  // Allow for customizing the behavior of calls to external symbols, including101  // when the analysis is explicitly marked as non-interprocedural.102  auto isExternalCallable = [&]() {103    auto callable =104        dyn_cast_if_present<CallableOpInterface>(call.resolveCallable());105    return callable && !callable.getCallableRegion();106  };107  if (!getSolverConfig().isInterprocedural() || isExternalCallable()) {108    LDBG() << "  Handling as external callee (non-interprocedural or external)";109    return visitCallControlFlowTransfer(110        call, CallControlFlowAction::ExternalCallee, before, after);111  }112 113  const auto *predecessors = getOrCreateFor<PredecessorState>(114      getProgramPointAfter(call.getOperation()), getProgramPointAfter(call));115  // Otherwise, if not all return sites are known, then conservatively assume we116  // can't reason about the data-flow.117  if (!predecessors->allPredecessorsKnown()) {118    LDBG() << "  Not all predecessors known, setting to entry state";119    return setToEntryState(after);120  }121 122  LDBG() << "  Processing " << predecessors->getKnownPredecessors().size()123         << " known predecessors";124  for (Operation *predecessor : predecessors->getKnownPredecessors()) {125    LDBG() << "    Processing predecessor: "126           << OpWithFlags(predecessor, OpPrintingFlags().skipRegions());127    // Get the lattices at callee return:128    //129    //   func.func @callee() {130    //     ...131    //     return  // predecessor132    //     // latticeAtCalleeReturn133    //   }134    //   func.func @caller() {135    //     ...136    //     call @callee137    //     // latticeAfterCall138    //     ...139    //   }140    AbstractDenseLattice *latticeAfterCall = after;141    const AbstractDenseLattice *latticeAtCalleeReturn =142        getLatticeFor(getProgramPointAfter(call.getOperation()),143                      getProgramPointAfter(predecessor));144    LDBG() << "    Lattice at callee return: " << *latticeAtCalleeReturn;145    visitCallControlFlowTransfer(call, CallControlFlowAction::ExitCallee,146                                 *latticeAtCalleeReturn, latticeAfterCall);147  }148}149 150LogicalResult151AbstractDenseForwardDataFlowAnalysis::processOperation(Operation *op) {152  LDBG() << "processOperation (forward): "153         << OpWithFlags(op, OpPrintingFlags().skipRegions());154  ProgramPoint *point = getProgramPointAfter(op);155  // If the containing block is not executable, bail out.156  if (op->getBlock() != nullptr &&157      !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))158           ->isLive()) {159    LDBG() << "  Block not executable, skipping operation";160    return success();161  }162 163  // Get the dense lattice to update.164  AbstractDenseLattice *after = getLattice(point);165 166  // Get the dense state before the execution of the op.167  const AbstractDenseLattice *before =168      getLatticeFor(point, getProgramPointBefore(op));169  LDBG() << "  before state: " << *before;170  LDBG() << "  after state: " << *after;171 172  // If this op implements region control-flow, then control-flow dictates its173  // transfer function.174  if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {175    LDBG() << "  Processing as region branch operation";176    visitRegionBranchOperation(point, branch, after);177    return success();178  }179 180  // If this is a call operation, then join its lattices across known return181  // sites.182  if (auto call = dyn_cast<CallOpInterface>(op)) {183    LDBG() << "  Processing as call operation";184    visitCallOperation(call, *before, after);185    return success();186  }187 188  // Invoke the operation transfer function.189  LDBG() << "  Invoking operation transfer function";190  return visitOperationImpl(op, *before, after);191}192 193void AbstractDenseForwardDataFlowAnalysis::visitBlock(Block *block) {194  LDBG() << "visitBlock (forward): " << block;195  // If the block is not executable, bail out.196  ProgramPoint *point = getProgramPointBefore(block);197  if (!getOrCreateFor<Executable>(point, point)->isLive()) {198    LDBG() << "  Block not executable, skipping";199    return;200  }201 202  // Get the dense lattice to update.203  AbstractDenseLattice *after = getLattice(point);204  LDBG() << "  Block lattice state: " << *after;205 206  // The dense lattices of entry blocks are set by region control-flow or the207  // callgraph.208  if (block->isEntryBlock()) {209    LDBG() << "  Processing entry block";210    // Check if this block is the entry block of a callable region.211    auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());212    if (callable && callable.getCallableRegion() == block->getParent()) {213      LDBG() << "    Entry block of callable region";214      const auto *callsites = getOrCreateFor<PredecessorState>(215          point, getProgramPointAfter(callable));216      // If not all callsites are known, conservatively mark all lattices as217      // having reached their pessimistic fixpoints. Do the same if218      // interprocedural analysis is not enabled.219      if (!callsites->allPredecessorsKnown() ||220          !getSolverConfig().isInterprocedural()) {221        LDBG() << "    Not all callsites known or non-interprocedural, setting "222                  "to entry state";223        return setToEntryState(after);224      }225      LDBG() << "    Processing " << callsites->getKnownPredecessors().size()226             << " known callsites";227      for (Operation *callsite : callsites->getKnownPredecessors()) {228        LDBG() << "      Processing callsite: "229               << OpWithFlags(callsite, OpPrintingFlags().skipRegions());230        // Get the dense lattice before the callsite.231        const AbstractDenseLattice *before;232        before = getLatticeFor(point, getProgramPointBefore(callsite));233        LDBG() << "      Lattice before callsite: " << *before;234 235        visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),236                                     CallControlFlowAction::EnterCallee,237                                     *before, after);238      }239      return;240    }241 242    // Check if we can reason about the control-flow.243    if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {244      LDBG() << "    Entry block of region branch operation";245      return visitRegionBranchOperation(point, branch, after);246    }247 248    // Otherwise, we can't reason about the data-flow.249    LDBG() << "    Cannot reason about data-flow, setting to entry state";250    return setToEntryState(after);251  }252 253  // Join the state with the state after the block's predecessors.254  LDBG() << "  Joining state from "255         << std::distance(block->pred_begin(), block->pred_end())256         << " predecessors";257  for (Block::pred_iterator it = block->pred_begin(), e = block->pred_end();258       it != e; ++it) {259    // Skip control edges that aren't executable.260    Block *predecessor = *it;261    if (!getOrCreateFor<Executable>(262             point, getLatticeAnchor<CFGEdge>(predecessor, block))263             ->isLive()) {264      LDBG() << "    Skipping non-executable edge from " << predecessor;265      continue;266    }267 268    LDBG() << "    Joining state from predecessor " << predecessor;269    const AbstractDenseLattice &before = *getLatticeFor(270        point, getProgramPointAfter(predecessor->getTerminator()));271    // Merge in the state from the predecessor's terminator.272    visitBlockTransfer(block, point, predecessor, before, after);273  }274}275 276void AbstractDenseForwardDataFlowAnalysis::visitRegionBranchOperation(277    ProgramPoint *point, RegionBranchOpInterface branch,278    AbstractDenseLattice *after) {279  LDBG() << "visitRegionBranchOperation (forward): "280         << OpWithFlags(branch.getOperation(), OpPrintingFlags().skipRegions());281  LDBG() << "  point: " << *point;282  LDBG() << "  after state: " << *after;283 284  // Get the terminator predecessors.285  const auto *predecessors = getOrCreateFor<PredecessorState>(point, point);286  assert(predecessors->allPredecessorsKnown() &&287         "unexpected unresolved region successors");288 289  LDBG() << "  Processing " << predecessors->getKnownPredecessors().size()290         << " known predecessors";291  for (Operation *op : predecessors->getKnownPredecessors()) {292    LDBG() << "    Processing predecessor: "293           << OpWithFlags(op, OpPrintingFlags().skipRegions());294    const AbstractDenseLattice *before;295    // If the predecessor is the parent, get the state before the parent.296    if (op == branch) {297      LDBG() << "      Predecessor is the branch itself, getting state before "298                "parent";299      before = getLatticeFor(point, getProgramPointBefore(op));300      // Otherwise, get the state after the terminator.301    } else {302      LDBG()303          << "      Predecessor is terminator, getting state after terminator";304      before = getLatticeFor(point, getProgramPointAfter(op));305    }306    LDBG() << "      before state: " << *before;307 308    // This function is called in two cases:309    //   1. when visiting the block (point = block start);310    //   2. when visiting the parent operation (point = iter after parent op).311    // In both cases, we are looking for predecessor operations of the point,312    //   1. predecessor may be the terminator of another block from another313    //   region (assuming that the block does belong to another region via an314    //   assertion) or the parent (when parent can transfer control to this315    //   region);316    //   2. predecessor may be the terminator of a block that exits the317    //   region (when region transfers control to the parent) or the operation318    //   before the parent.319    // In the latter case, just perform the join as it isn't the control flow320    // affected by the region.321    std::optional<unsigned> regionFrom =322        op == branch ? std::optional<unsigned>()323                     : op->getBlock()->getParent()->getRegionNumber();324    LDBG() << "      regionFrom: "325           << (regionFrom ? std::to_string(*regionFrom) : "parent");326 327    if (point->isBlockStart()) {328      unsigned regionTo = point->getBlock()->getParent()->getRegionNumber();329      LDBG() << "      Point is block start, regionTo: " << regionTo;330      LDBG() << "      Calling visitRegionBranchControlFlowTransfer with "331                "regionFrom/regionTo";332      visitRegionBranchControlFlowTransfer(branch, regionFrom, regionTo,333                                           *before, after);334    } else {335      assert(point->getPrevOp() == branch &&336             "expected to be visiting the branch itself");337      LDBG() << "      Point is not block start, checking if predecessor is "338                "region or op itself";339      // Only need to call the arc transfer when the predecessor is the region340      // or the op itself, not the previous op.341      if (op->getParentOp() == branch || op == branch) {342        LDBG() << "      Predecessor is region or op itself, calling "343                  "visitRegionBranchControlFlowTransfer";344        visitRegionBranchControlFlowTransfer(345            branch, regionFrom, /*regionTo=*/std::nullopt, *before, after);346      } else {347        LDBG()348            << "      Predecessor is not region or op itself, performing join";349        join(after, *before);350      }351    }352  }353}354 355//===----------------------------------------------------------------------===//356// AbstractDenseBackwardDataFlowAnalysis357//===----------------------------------------------------------------------===//358 359void AbstractDenseBackwardDataFlowAnalysis::initializeEquivalentLatticeAnchor(360    Operation *top) {361  LDBG() << "initializeEquivalentLatticeAnchor (backward): "362         << OpWithFlags(top, OpPrintingFlags().skipRegions());363  top->walk([&](Operation *op) {364    if (isa<RegionBranchOpInterface, CallOpInterface>(op)) {365      LDBG() << "  Skipping "366             << OpWithFlags(op, OpPrintingFlags().skipRegions())367             << " (region branch or call)";368      return;369    }370    LDBG() << "  Building equivalent lattice anchor for "371           << OpWithFlags(op, OpPrintingFlags().skipRegions());372    buildOperationEquivalentLatticeAnchor(op);373  });374}375 376LogicalResult377AbstractDenseBackwardDataFlowAnalysis::initialize(Operation *top) {378  LDBG() << "initialize (backward): "379         << OpWithFlags(top, OpPrintingFlags().skipRegions());380  // Visit every operation and block.381  if (failed(processOperation(top))) {382    LDBG() << "  Failed to process top-level operation";383    return failure();384  }385 386  for (Region &region : top->getRegions()) {387    LDBG() << "  Processing region with " << region.getBlocks().size()388           << " blocks";389    for (Block &block : region) {390      LDBG() << "    Processing block with " << block.getOperations().size()391             << " operations";392      visitBlock(&block);393      for (Operation &op : llvm::reverse(block)) {394        LDBG() << "      Initializing operation (backward): "395               << OpWithFlags(&op, OpPrintingFlags().skipRegions());396        if (failed(initialize(&op))) {397          LDBG() << "      Failed to initialize operation";398          return failure();399        }400      }401    }402  }403  LDBG() << "  Backward initialization completed successfully";404  return success();405}406 407LogicalResult408AbstractDenseBackwardDataFlowAnalysis::visit(ProgramPoint *point) {409  LDBG() << "visit (backward): " << *point;410  if (!point->isBlockEnd()) {411    LDBG() << "  Processing operation: "412           << OpWithFlags(point->getNextOp(), OpPrintingFlags().skipRegions());413    return processOperation(point->getNextOp());414  }415  LDBG() << "  Visiting block: " << point->getBlock();416  visitBlock(point->getBlock());417  return success();418}419 420void AbstractDenseBackwardDataFlowAnalysis::visitCallOperation(421    CallOpInterface call, const AbstractDenseLattice &after,422    AbstractDenseLattice *before) {423  LDBG() << "visitCallOperation (backward): "424         << OpWithFlags(call.getOperation(), OpPrintingFlags().skipRegions());425  LDBG() << "  after state: " << after;426  LDBG() << "  before state: " << *before;427 428  // If the solver is not interprocedural, let the hook handle it as an external429  // callee.430  if (!getSolverConfig().isInterprocedural()) {431    LDBG() << "  Non-interprocedural analysis, handling as external callee";432    return visitCallControlFlowTransfer(433        call, CallControlFlowAction::ExternalCallee, after, before);434  }435 436  // Find the callee.437  Operation *callee = call.resolveCallableInTable(&symbolTable);438  if (callee) {439    LDBG() << "  Resolved callee: "440           << OpWithFlags(callee, OpPrintingFlags().skipRegions());441  } else {442    LDBG() << "  Resolved callee: null";443  }444 445  auto callable = dyn_cast_or_null<CallableOpInterface>(callee);446  // No region means the callee is only declared in this module.447  // If that is the case or if the solver is not interprocedural,448  // let the hook handle it.449  if (callable && (!callable.getCallableRegion() ||450                   callable.getCallableRegion()->empty())) {451    LDBG() << "  Callee has no region or empty region, handling as external "452              "callee";453    return visitCallControlFlowTransfer(454        call, CallControlFlowAction::ExternalCallee, after, before);455  }456 457  if (!callable) {458    LDBG() << "  No callable found, setting to exit state";459    return setToExitState(before);460  }461 462  Region *region = callable.getCallableRegion();463  LDBG() << "  Processing callable with region";464 465  // Call-level control flow specifies the data flow here.466  //467  //   func.func @callee() {468  //     ^calleeEntryBlock:469  //     // latticeAtCalleeEntry470  //     ...471  //   }472  //   func.func @caller() {473  //     ...474  //     // latticeBeforeCall475  //     call @callee476  //     ...477  //   }478  Block *calleeEntryBlock = &region->front();479  ProgramPoint *calleeEntry = getProgramPointBefore(calleeEntryBlock);480  const AbstractDenseLattice &latticeAtCalleeEntry =481      *getLatticeFor(getProgramPointBefore(call.getOperation()), calleeEntry);482  LDBG() << "  Lattice at callee entry: " << latticeAtCalleeEntry;483  AbstractDenseLattice *latticeBeforeCall = before;484  visitCallControlFlowTransfer(call, CallControlFlowAction::EnterCallee,485                               latticeAtCalleeEntry, latticeBeforeCall);486}487 488LogicalResult489AbstractDenseBackwardDataFlowAnalysis::processOperation(Operation *op) {490  LDBG() << "processOperation (backward): "491         << OpWithFlags(op, OpPrintingFlags().skipRegions());492  ProgramPoint *point = getProgramPointBefore(op);493  // If the containing block is not executable, bail out.494  if (op->getBlock() != nullptr &&495      !getOrCreateFor<Executable>(point, getProgramPointBefore(op->getBlock()))496           ->isLive()) {497    LDBG() << "  Block not executable, skipping operation";498    return success();499  }500 501  // Get the dense lattice to update.502  AbstractDenseLattice *before = getLattice(point);503 504  // Get the dense state after execution of this op.505  const AbstractDenseLattice *after =506      getLatticeFor(point, getProgramPointAfter(op));507  LDBG() << "  before state: " << *before;508  LDBG() << "  after state: " << *after;509 510  // Special cases where control flow may dictate data flow.511  if (auto branch = dyn_cast<RegionBranchOpInterface>(op)) {512    LDBG() << "  Processing as region branch operation";513    visitRegionBranchOperation(point, branch, RegionBranchPoint::parent(),514                               before);515    return success();516  }517  if (auto call = dyn_cast<CallOpInterface>(op)) {518    LDBG() << "  Processing as call operation";519    visitCallOperation(call, *after, before);520    return success();521  }522 523  // Invoke the operation transfer function.524  LDBG() << "  Invoking operation transfer function";525  return visitOperationImpl(op, *after, before);526}527 528void AbstractDenseBackwardDataFlowAnalysis::visitBlock(Block *block) {529  LDBG() << "visitBlock (backward): " << block;530  ProgramPoint *point = getProgramPointAfter(block);531  // If the block is not executable, bail out.532  if (!getOrCreateFor<Executable>(point, getProgramPointBefore(block))533           ->isLive()) {534    LDBG() << "  Block not executable, skipping";535    return;536  }537 538  AbstractDenseLattice *before = getLattice(point);539  LDBG() << "  Block lattice state: " << *before;540 541  // We need "exit" blocks, i.e. the blocks that may return control to the542  // parent operation.543  auto isExitBlock = [](Block *b) {544    // Treat empty and terminator-less blocks as exit blocks.545    if (b->empty() || !b->back().mightHaveTrait<OpTrait::IsTerminator>())546      return true;547 548    // There may be a weird case where a terminator may be transferring control549    // either to the parent or to another block, so exit blocks and successors550    // are not mutually exclusive.551    return isa_and_nonnull<RegionBranchTerminatorOpInterface>(552        b->getTerminator());553  };554  if (isExitBlock(block)) {555    LDBG() << "  Processing exit block";556    // If this block is exiting from a callable, the successors of exiting from557    // a callable are the successors of all call sites. And the call sites558    // themselves are predecessors of the callable.559    auto callable = dyn_cast<CallableOpInterface>(block->getParentOp());560    if (callable && callable.getCallableRegion() == block->getParent()) {561      LDBG() << "    Exit block of callable region";562      const auto *callsites = getOrCreateFor<PredecessorState>(563          point, getProgramPointAfter(callable));564      // If not all call sites are known, conservative mark all lattices as565      // having reached their pessimistic fix points.566      if (!callsites->allPredecessorsKnown() ||567          !getSolverConfig().isInterprocedural()) {568        LDBG() << "    Not all callsites known or non-interprocedural, setting "569                  "to exit state";570        return setToExitState(before);571      }572 573      LDBG() << "    Processing " << callsites->getKnownPredecessors().size()574             << " known callsites";575      for (Operation *callsite : callsites->getKnownPredecessors()) {576        LDBG() << "      Processing callsite: "577               << OpWithFlags(callsite, OpPrintingFlags().skipRegions());578        const AbstractDenseLattice *after =579            getLatticeFor(point, getProgramPointAfter(callsite));580        LDBG() << "      Lattice after callsite: " << *after;581        visitCallControlFlowTransfer(cast<CallOpInterface>(callsite),582                                     CallControlFlowAction::ExitCallee, *after,583                                     before);584      }585      return;586    }587 588    // If this block is exiting from an operation with region-based control589    // flow, propagate the lattice back along the control flow edge.590    if (auto branch = dyn_cast<RegionBranchOpInterface>(block->getParentOp())) {591      LDBG() << "    Exit block of region branch operation";592      auto terminator =593          cast<RegionBranchTerminatorOpInterface>(block->getTerminator());594      visitRegionBranchOperation(point, branch, terminator, before);595      return;596    }597 598    // Cannot reason about successors of an exit block, set the pessimistic599    // fixpoint.600    LDBG() << "    Cannot reason about successors, setting to exit state";601    return setToExitState(before);602  }603 604  // Meet the state with the state before block's successors.605  LDBG() << "  Meeting state from " << block->getSuccessors().size()606         << " successors";607  for (Block *successor : block->getSuccessors()) {608    if (!getOrCreateFor<Executable>(point,609                                    getLatticeAnchor<CFGEdge>(block, successor))610             ->isLive()) {611      LDBG() << "    Skipping non-executable edge to " << successor;612      continue;613    }614 615    LDBG() << "    Meeting state from successor " << successor;616    // Merge in the state from the successor: either the first operation, or the617    // block itself when empty.618    visitBlockTransfer(block, point, successor,619                       *getLatticeFor(point, getProgramPointBefore(successor)),620                       before);621  }622}623 624void AbstractDenseBackwardDataFlowAnalysis::visitRegionBranchOperation(625    ProgramPoint *point, RegionBranchOpInterface branch,626    RegionBranchPoint branchPoint, AbstractDenseLattice *before) {627  LDBG() << "visitRegionBranchOperation (backward): "628         << OpWithFlags(branch.getOperation(), OpPrintingFlags().skipRegions());629  LDBG() << "  branchPoint: " << (branchPoint.isParent() ? "parent" : "region");630  LDBG() << "  before state: " << *before;631 632  // The successors of the operation may be either the first operation of the633  // entry block of each possible successor region, or the next operation when634  // the branch is a successor of itself.635  SmallVector<RegionSuccessor> successors;636  branch.getSuccessorRegions(branchPoint, successors);637  LDBG() << "  Processing " << successors.size() << " successor regions";638  for (const RegionSuccessor &successor : successors) {639    const AbstractDenseLattice *after;640    if (successor.isParent() || successor.getSuccessor()->empty()) {641      LDBG() << "    Successor is parent or empty region";642      after = getLatticeFor(point, getProgramPointAfter(branch));643    } else {644      Region *successorRegion = successor.getSuccessor();645      assert(!successorRegion->empty() && "unexpected empty successor region");646      Block *successorBlock = &successorRegion->front();647      LDBG() << "    Successor region with "648             << successorRegion->getBlocks().size() << " blocks";649 650      if (!getOrCreateFor<Executable>(point,651                                      getProgramPointBefore(successorBlock))652               ->isLive()) {653        LDBG() << "    Successor block not executable, skipping";654        continue;655      }656 657      after = getLatticeFor(point, getProgramPointBefore(successorBlock));658    }659    LDBG() << "    After state: " << *after;660 661    visitRegionBranchControlFlowTransfer(branch, branchPoint, successor, *after,662                                         before);663  }664}665