[llvm] r369765 - [MustExec] Add a generic "must-be-executed-context" explorer

Johannes Doerfert via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 08:17:27 PDT 2019


Author: jdoerfert
Date: Fri Aug 23 08:17:27 2019
New Revision: 369765

URL: http://llvm.org/viewvc/llvm-project?rev=369765&view=rev
Log:
[MustExec] Add a generic "must-be-executed-context" explorer

Given an instruction I, the MustBeExecutedContextExplorer allows to
easily traverse instructions that are guaranteed to be executed whenever
I is. For now, these instruction have to be statically "after" I, in
the same or different basic blocks.

This patch also adds a pass which prints the must-be-executed-context
for each instruction in a module. It is used to test the
MustBeExecutedContextExplorer, for now on the examples given in the
class comment of the MustBeExecutedIterator.

Differential Revision: https://reviews.llvm.org/D65186

Added:
    llvm/trunk/test/Analysis/MustExecute/must_be_executed_context.ll
Modified:
    llvm/trunk/include/llvm/Analysis/MustExecute.h
    llvm/trunk/include/llvm/Analysis/Passes.h
    llvm/trunk/include/llvm/InitializePasses.h
    llvm/trunk/include/llvm/LinkAllPasses.h
    llvm/trunk/lib/Analysis/Analysis.cpp
    llvm/trunk/lib/Analysis/MustExecute.cpp

Modified: llvm/trunk/include/llvm/Analysis/MustExecute.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/MustExecute.h?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/MustExecute.h (original)
+++ llvm/trunk/include/llvm/Analysis/MustExecute.h Fri Aug 23 08:17:27 2019
@@ -7,10 +7,17 @@
 //===----------------------------------------------------------------------===//
 /// \file
 /// Contains a collection of routines for determining if a given instruction is
-/// guaranteed to execute if a given point in control flow is reached.  The most
+/// guaranteed to execute if a given point in control flow is reached. The most
 /// common example is an instruction within a loop being provably executed if we
 /// branch to the header of it's containing loop.
 ///
+/// There are two interfaces available to determine if an instruction is
+/// executed once a given point in the control flow is reached:
+/// 1) A loop-centric one derived from LoopSafetyInfo.
+/// 2) A "must be executed context"-based one implemented in the
+///    MustBeExecutedContextExplorer.
+/// Please refer to the class comments for more information.
+///
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_ANALYSIS_MUSTEXECUTE_H
@@ -164,6 +171,280 @@ public:
   virtual ~ICFLoopSafetyInfo() {};
 };
 
-}
+struct MustBeExecutedContextExplorer;
+
+/// Must be executed iterators visit stretches of instructions that are
+/// guaranteed to be executed together, potentially with other instruction
+/// executed in-between.
+///
+/// Given the following code, and assuming all statements are single
+/// instructions which transfer execution to the successor (see
+/// isGuaranteedToTransferExecutionToSuccessor), there are two possible
+/// outcomes. If we start the iterator at A, B, or E, we will visit only A, B,
+/// and E. If we start at C or D, we will visit all instructions A-E.
+///
+/// \code
+///   A;
+///   B;
+///   if (...) {
+///     C;
+///     D;
+///   }
+///   E;
+/// \endcode
+///
+///
+/// Below is the example extneded with instructions F and G. Now we assume F
+/// might not transfer execution to it's successor G. As a result we get the
+/// following visit sets:
+///
+/// Start Instruction   | Visit Set
+/// A                   | A, B,       E, F
+///    B                | A, B,       E, F
+///       C             | A, B, C, D, E, F
+///          D          | A, B, C, D, E, F
+///             E       | A, B,       E, F
+///                F    | A, B,       E, F
+///                   G | A, B,       E, F, G
+///
+///
+/// \code
+///   A;
+///   B;
+///   if (...) {
+///     C;
+///     D;
+///   }
+///   E;
+///   F;  // Might not transfer execution to its successor G.
+///   G;
+/// \endcode
+///
+///
+/// A more complex example involving conditionals, loops, break, and continue
+/// is shown below. We again assume all instructions will transmit control to
+/// the successor and we assume we can prove the inner loop to be finite. We
+/// omit non-trivial branch conditions as the exploration is oblivious to them.
+/// Constant branches are assumed to be unconditional in the CFG. The resulting
+/// visist sets are shown in the table below.
+///
+/// \code
+///   A;
+///   while (true) {
+///     B;
+///     if (...)
+///       C;
+///     if (...)
+///       continue;
+///     D;
+///     if (...)
+///       break;
+///     do {
+///       if (...)
+///         continue;
+///       E;
+///     } while (...);
+///     F;
+///   }
+///   G;
+/// \endcode
+///
+/// Start Instruction    | Visit Set
+/// A                    | A, B
+///    B                 | A, B
+///       C              | A, B, C
+///          D           | A, B,    D
+///             E        | A, B,    D, E, F
+///                F     | A, B,    D,    F
+///                   G  | A, B,    D,       G
+///
+///
+/// Note that the examples show optimal visist sets but not necessarily the ones
+/// derived by the explorer depending on the available CFG analyses (see
+/// MustBeExecutedContextExplorer). Also note that we, depending on the options,
+/// the visit set can contain instructions from other functions.
+struct MustBeExecutedIterator {
+  /// Type declarations that make his class an input iterator.
+  ///{
+  typedef const Instruction *value_type;
+  typedef std::ptrdiff_t difference_type;
+  typedef const Instruction **pointer;
+  typedef const Instruction *&reference;
+  typedef std::input_iterator_tag iterator_category;
+  ///}
+
+  using ExplorerTy = MustBeExecutedContextExplorer;
+
+  MustBeExecutedIterator(const MustBeExecutedIterator &Other)
+      : Visited(Other.Visited), Explorer(Other.Explorer),
+        CurInst(Other.CurInst) {}
+
+  MustBeExecutedIterator(MustBeExecutedIterator &&Other)
+      : Visited(std::move(Other.Visited)), Explorer(Other.Explorer),
+        CurInst(Other.CurInst) {}
+
+  MustBeExecutedIterator &operator=(MustBeExecutedIterator &&Other) {
+    if (this != &Other) {
+      std::swap(Visited, Other.Visited);
+      std::swap(CurInst, Other.CurInst);
+    }
+    return *this;
+  }
+
+  ~MustBeExecutedIterator() {}
+
+  /// Pre- and post-increment operators.
+  ///{
+  MustBeExecutedIterator &operator++() {
+    CurInst = advance();
+    return *this;
+  }
+
+  MustBeExecutedIterator operator++(int) {
+    MustBeExecutedIterator tmp(*this);
+    operator++();
+    return tmp;
+  }
+  ///}
+
+  /// Equality and inequality operators. Note that we ignore the history here.
+  ///{
+  bool operator==(const MustBeExecutedIterator &Other) const {
+    return CurInst == Other.CurInst;
+  }
+
+  bool operator!=(const MustBeExecutedIterator &Other) const {
+    return !(*this == Other);
+  }
+  ///}
+
+  /// Return the underlying instruction.
+  const Instruction *&operator*() { return CurInst; }
+  const Instruction *getCurrentInst() const { return CurInst; }
+
+  /// Return true if \p I was encountered by this iterator already.
+  bool count(const Instruction *I) const { return Visited.count(I); }
+
+private:
+  using VisitedSetTy = DenseSet<const Instruction *>;
+
+  /// Private constructors.
+  MustBeExecutedIterator(ExplorerTy &Explorer, const Instruction *I);
+
+  /// Reset the iterator to its initial state pointing at \p I.
+  void reset(const Instruction *I);
+
+  /// Try to advance one of the underlying positions (Head or Tail).
+  ///
+  /// \return The next instruction in the must be executed context, or nullptr
+  ///         if none was found.
+  const Instruction *advance();
+
+  /// A set to track the visited instructions in order to deal with endless
+  /// loops and recursion.
+  VisitedSetTy Visited;
+
+  /// A reference to the explorer that created this iterator.
+  ExplorerTy &Explorer;
+
+  /// The instruction we are currently exposing to the user. There is always an
+  /// instruction that we know is executed with the given program point,
+  /// initially the program point itself.
+  const Instruction *CurInst;
+
+  friend struct MustBeExecutedContextExplorer;
+};
+
+/// A "must be executed context" for a given program point PP is the set of
+/// instructions, potentially before and after PP, that are executed always when
+/// PP is reached. The MustBeExecutedContextExplorer an interface to explore
+/// "must be executed contexts" in a module through the use of
+/// MustBeExecutedIterator.
+///
+/// The explorer exposes "must be executed iterators" that traverse the must be
+/// executed context. There is little information sharing between iterators as
+/// the expected use case involves few iterators for "far apart" instructions.
+/// If that changes, we should consider caching more intermediate results.
+struct MustBeExecutedContextExplorer {
+
+  /// In the description of the parameters we use PP to denote a program point
+  /// for which the must be executed context is explored, or put differently,
+  /// for which the MustBeExecutedIterator is created.
+  ///
+  /// \param ExploreInterBlock    Flag to indicate if instructions in blocks
+  ///                             other than the parent of PP should be
+  ///                             explored.
+  MustBeExecutedContextExplorer(bool ExploreInterBlock)
+      : ExploreInterBlock(ExploreInterBlock), EndIterator(*this, nullptr) {}
+
+  /// Clean up the dynamically allocated iterators.
+  ~MustBeExecutedContextExplorer() {
+    DeleteContainerSeconds(InstructionIteratorMap);
+  }
+
+  /// Iterator-based interface. \see MustBeExecutedIterator.
+  ///{
+  using iterator = MustBeExecutedIterator;
+  using const_iterator = const MustBeExecutedIterator;
+
+  /// Return an iterator to explore the context around \p PP.
+  iterator &begin(const Instruction *PP) {
+    auto *&It = InstructionIteratorMap[PP];
+    if (!It)
+      It = new iterator(*this, PP);
+    return *It;
+  }
+
+  /// Return an iterator to explore the cached context around \p PP.
+  const_iterator &begin(const Instruction *PP) const {
+    return *InstructionIteratorMap.lookup(PP);
+  }
+
+  /// Return an universal end iterator.
+  ///{
+  iterator &end() { return EndIterator; }
+  iterator &end(const Instruction *) { return EndIterator; }
+
+  const_iterator &end() const { return EndIterator; }
+  const_iterator &end(const Instruction *) const { return EndIterator; }
+  ///}
+
+  /// Return an iterator range to explore the context around \p PP.
+  llvm::iterator_range<iterator> range(const Instruction *PP) {
+    return llvm::make_range(begin(PP), end(PP));
+  }
+
+  /// Return an iterator range to explore the cached context around \p PP.
+  llvm::iterator_range<const_iterator> range(const Instruction *PP) const {
+    return llvm::make_range(begin(PP), end(PP));
+  }
+  ///}
+
+  /// Return the next instruction that is guaranteed to be executed after \p PP.
+  ///
+  /// \param It              The iterator that is used to traverse the must be
+  ///                        executed context.
+  /// \param PP              The program point for which the next instruction
+  ///                        that is guaranteed to execute is determined.
+  const Instruction *
+  getMustBeExecutedNextInstruction(MustBeExecutedIterator &It,
+                                   const Instruction *PP);
+
+  /// Parameter that limit the performed exploration. See the constructor for
+  /// their meaning.
+  ///{
+  const bool ExploreInterBlock;
+  ///}
+
+private:
+  /// Map from instructions to associated must be executed iterators.
+  DenseMap<const Instruction *, MustBeExecutedIterator *>
+      InstructionIteratorMap;
+
+  /// A unique end iterator.
+  MustBeExecutedIterator EndIterator;
+};
+
+} // namespace llvm
 
 #endif

Modified: llvm/trunk/include/llvm/Analysis/Passes.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/Passes.h?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/Passes.h (original)
+++ llvm/trunk/include/llvm/Analysis/Passes.h Fri Aug 23 08:17:27 2019
@@ -103,6 +103,13 @@ namespace llvm {
   //
   FunctionPass *createMustExecutePrinter();
 
+  //===--------------------------------------------------------------------===//
+  //
+  // createMustBeExecutedContextPrinter - This pass prints information about which
+  // instructions are guaranteed to execute together (run with -analyze).
+  //
+  ModulePass *createMustBeExecutedContextPrinter();
+
 }
 
 #endif

Modified: llvm/trunk/include/llvm/InitializePasses.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/include/llvm/InitializePasses.h (original)
+++ llvm/trunk/include/llvm/InitializePasses.h Fri Aug 23 08:17:27 2019
@@ -289,6 +289,7 @@ void initializeMetaRenamerPass(PassRegis
 void initializeModuleDebugInfoPrinterPass(PassRegistry&);
 void initializeModuleSummaryIndexWrapperPassPass(PassRegistry&);
 void initializeMustExecutePrinterPass(PassRegistry&);
+void initializeMustBeExecutedContextPrinterPass(PassRegistry&);
 void initializeNameAnonGlobalLegacyPassPass(PassRegistry&);
 void initializeNaryReassociateLegacyPassPass(PassRegistry&);
 void initializeNewGVNLegacyPassPass(PassRegistry&);

Modified: llvm/trunk/include/llvm/LinkAllPasses.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/LinkAllPasses.h?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/include/llvm/LinkAllPasses.h (original)
+++ llvm/trunk/include/llvm/LinkAllPasses.h Fri Aug 23 08:17:27 2019
@@ -219,6 +219,7 @@ namespace {
       (void) llvm::createStraightLineStrengthReducePass();
       (void) llvm::createMemDerefPrinter();
       (void) llvm::createMustExecutePrinter();
+      (void) llvm::createMustBeExecutedContextPrinter();
       (void) llvm::createFloat2IntPass();
       (void) llvm::createEliminateAvailableExternallyPass();
       (void) llvm::createScalarizeMaskedMemIntrinPass();

Modified: llvm/trunk/lib/Analysis/Analysis.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Analysis.cpp?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/Analysis.cpp (original)
+++ llvm/trunk/lib/Analysis/Analysis.cpp Fri Aug 23 08:17:27 2019
@@ -65,6 +65,7 @@ void llvm::initializeAnalysis(PassRegist
   initializeModuleDebugInfoPrinterPass(Registry);
   initializeModuleSummaryIndexWrapperPassPass(Registry);
   initializeMustExecutePrinterPass(Registry);
+  initializeMustBeExecutedContextPrinterPass(Registry);
   initializeObjCARCAAWrapperPassPass(Registry);
   initializeOptimizationRemarkEmitterWrapperPassPass(Registry);
   initializePhiValuesWrapperPassPass(Registry);

Modified: llvm/trunk/lib/Analysis/MustExecute.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MustExecute.cpp?rev=369765&r1=369764&r2=369765&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/MustExecute.cpp (original)
+++ llvm/trunk/lib/Analysis/MustExecute.cpp Fri Aug 23 08:17:27 2019
@@ -7,6 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Analysis/MustExecute.h"
+#include "llvm/ADT/PostOrderIterator.h"
+#include "llvm/Analysis/CFG.h"
 #include "llvm/Analysis/InstructionSimplify.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/Passes.h"
@@ -19,8 +21,11 @@
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
 #include "llvm/Support/raw_ostream.h"
+
 using namespace llvm;
 
+#define DEBUG_TYPE "must-execute"
+
 const DenseMap<BasicBlock *, ColorVector> &
 LoopSafetyInfo::getBlockColors() const {
   return BlockColors;
@@ -306,6 +311,17 @@ namespace {
     }
     bool runOnFunction(Function &F) override;
   };
+  struct MustBeExecutedContextPrinter : public ModulePass {
+    static char ID;
+
+    MustBeExecutedContextPrinter() : ModulePass(ID) {
+      initializeMustBeExecutedContextPrinterPass(*PassRegistry::getPassRegistry());
+    }
+    void getAnalysisUsage(AnalysisUsage &AU) const override {
+      AU.setPreservesAll();
+    }
+    bool runOnModule(Module &M) override;
+  };
 }
 
 char MustExecutePrinter::ID = 0;
@@ -320,6 +336,36 @@ FunctionPass *llvm::createMustExecutePri
   return new MustExecutePrinter();
 }
 
+char MustBeExecutedContextPrinter::ID = 0;
+INITIALIZE_PASS_BEGIN(
+    MustBeExecutedContextPrinter, "print-must-be-executed-contexts",
+    "print the must-be-executed-contexed for all instructions", false, true)
+INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
+INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+INITIALIZE_PASS_END(MustBeExecutedContextPrinter,
+                    "print-must-be-executed-contexts",
+                    "print the must-be-executed-contexed for all instructions",
+                    false, true)
+
+ModulePass *llvm::createMustBeExecutedContextPrinter() {
+  return new MustBeExecutedContextPrinter();
+}
+
+bool MustBeExecutedContextPrinter::runOnModule(Module &M) {
+  MustBeExecutedContextExplorer Explorer(true);
+  for (Function &F : M) {
+    for (Instruction &I : instructions(F)) {
+      dbgs() << "-- Explore context of: " << I << "\n";
+      for (const Instruction *CI : Explorer.range(&I))
+        dbgs() << "  [F: " << CI->getFunction()->getName() << "] " << *CI
+               << "\n";
+    }
+  }
+
+  return false;
+}
+
 static bool isMustExecuteIn(const Instruction &I, Loop *L, DominatorTree *DT) {
   // TODO: merge these two routines.  For the moment, we display the best
   // result obtained by *either* implementation.  This is a bit unfair since no
@@ -396,3 +442,75 @@ bool MustExecutePrinter::runOnFunction(F
 
   return false;
 }
+
+const Instruction *
+MustBeExecutedContextExplorer::getMustBeExecutedNextInstruction(
+    MustBeExecutedIterator &It, const Instruction *PP) {
+  if (!PP)
+    return PP;
+  LLVM_DEBUG(dbgs() << "Find next instruction for " << *PP << "\n");
+
+  // If we explore only inside a given basic block we stop at terminators.
+  if (!ExploreInterBlock && PP->isTerminator()) {
+    LLVM_DEBUG(dbgs() << "\tReached terminator in intra-block mode, done\n");
+    return nullptr;
+  }
+
+  // If we do not traverse the call graph we check if we can make progress in
+  // the current function. First, check if the instruction is guaranteed to
+  // transfer execution to the successor.
+  bool TransfersExecution = isGuaranteedToTransferExecutionToSuccessor(PP);
+  if (!TransfersExecution)
+    return nullptr;
+
+  // If this is not a terminator we know that there is a single instruction
+  // after this one that is executed next if control is transfered. If not,
+  // we can try to go back to a call site we entered earlier. If none exists, we
+  // do not know any instruction that has to be executd next.
+  if (!PP->isTerminator()) {
+    const Instruction *NextPP = PP->getNextNode();
+    LLVM_DEBUG(dbgs() << "\tIntermediate instruction does transfer control\n");
+    return NextPP;
+  }
+
+  // Finally, we have to handle terminators, trivial ones first.
+  assert(PP->isTerminator() && "Expected a terminator!");
+
+  // A terminator without a successor is not handled yet.
+  if (PP->getNumSuccessors() == 0) {
+    LLVM_DEBUG(dbgs() << "\tUnhandled terminator\n");
+    return nullptr;
+  }
+
+  // A terminator with a single successor, we will continue at the beginning of
+  // that one.
+  if (PP->getNumSuccessors() == 1) {
+    LLVM_DEBUG(
+        dbgs() << "\tUnconditional terminator, continue with successor\n");
+    return &PP->getSuccessor(0)->front();
+  }
+
+  LLVM_DEBUG(dbgs() << "\tNo join point found\n");
+  return nullptr;
+}
+
+MustBeExecutedIterator::MustBeExecutedIterator(
+    MustBeExecutedContextExplorer &Explorer, const Instruction *I)
+    : Explorer(Explorer), CurInst(I) {
+  reset(I);
+}
+
+void MustBeExecutedIterator::reset(const Instruction *I) {
+  CurInst = I;
+  Visited.clear();
+  Visited.insert(I);
+}
+
+const Instruction *MustBeExecutedIterator::advance() {
+  assert(CurInst && "Cannot advance an end iterator!");
+  const Instruction *Next =
+      Explorer.getMustBeExecutedNextInstruction(*this, CurInst);
+  if (Next && !Visited.insert(Next).second)
+    Next = nullptr;
+  return Next;
+}

Added: llvm/trunk/test/Analysis/MustExecute/must_be_executed_context.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/MustExecute/must_be_executed_context.ll?rev=369765&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/MustExecute/must_be_executed_context.ll (added)
+++ llvm/trunk/test/Analysis/MustExecute/must_be_executed_context.ll Fri Aug 23 08:17:27 2019
@@ -0,0 +1,282 @@
+; RUN: opt -print-mustexecute               -analyze 2>&1 < %s | FileCheck %s --check-prefix=ME
+; RUN: opt -print-must-be-executed-contexts -analyze 2>&1 < %s | FileCheck %s --check-prefix=MBEC
+;
+;    void simple_conditional(int c) {
+;      A();
+;      B();
+;      if (c) {
+;        C();
+;        D();
+;      }
+;      E();
+;      F();
+;      G();
+;    }
+;
+; Best result:
+; Start Instruction   | Visit Set
+; A                   | A, B,       E, F
+;    B                | A, B,       E, F
+;       C             | A, B, C, D, E, F
+;          D          | A, B, C, D, E, F
+;             E       | A, B,       E, F
+;                F    | A, B,       E, F
+;                   G | A, B,       E, F, G
+;
+; FIXME: We miss the B -> E and backward exploration.
+;
+; There are no loops so print-mustexec will not do anything.
+; ME-NOT: mustexec
+;
+define void @simple_conditional(i32 %arg) {
+bb:
+  call void @A()
+; MBEC:      -- Explore context of:   call void @A()
+; MBEC-NEXT:   [F: simple_conditional]   call void @A()
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NOT:    call
+
+  call void @B()
+; MBEC:      -- Explore context of:   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   call void @B()
+; MBEC-NEXT:   [F: simple_conditional]   %tmp = icmp eq i32 %arg, 0
+; MBEC-NEXT:   [F: simple_conditional]   br i1 %tmp, label %bb2, label %bb1
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: %tmp
+
+  %tmp = icmp eq i32 %arg, 0
+  br i1 %tmp, label %bb2, label %bb1
+
+bb1:                                              ; preds = %bb
+  call void @C()
+; MBEC:      -- Explore context of:   call void @C()
+; MBEC-NEXT:   [F: simple_conditional]   call void @C()
+; MBEC-NEXT:   [F: simple_conditional]   call void @D()
+; MBEC-NEXT:   [F: simple_conditional]   br label %bb2
+; MBEC-NEXT:   [F: simple_conditional]   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NOT:    call
+
+  call void @D()
+; MBEC:      -- Explore context of:   call void @D()
+; MBEC-NEXT:   [F: simple_conditional]   call void @D()
+; MBEC-NEXT:   [F: simple_conditional]   br label %bb2
+; MBEC-NEXT:   [F: simple_conditional]   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: br
+
+  br label %bb2
+
+bb2:                                              ; preds = %bb, %bb1
+  call void @E()
+; MBEC:      -- Explore context of:   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   call void @E()
+; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NOT:    call
+
+  call void @F() ; might not return!
+; MBEC:      -- Explore context of:   call void @F()
+; MBEC-NEXT:   [F: simple_conditional]   call void @F()
+; MBEC-NOT:    call
+
+  call void @G()
+; MBEC:      -- Explore context of:   call void @G()
+; MBEC-NEXT:   [F: simple_conditional]   call void @G()
+; MBEC-NEXT:   [F: simple_conditional]   ret void
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: ret
+
+  ret void
+}
+
+
+;    void complex_loops_and_control(int c, int d) {
+;      A();
+;      while (1) {
+;        B();
+;        if (++c == d)
+;          C();
+;        if (++c == d)
+;          continue;
+;        D();
+;        if (++c == d)
+;          break;
+;        do {
+;          if (++c == d)
+;            continue;
+;          E();
+;        } while (++c == d);
+;        F();
+;      }
+;      G();
+;    }
+;
+; Best result:
+; Start Instruction    | Visit Set
+; A                    | A, B
+;    B                 | A, B
+;       C              | A, B, C
+;          D           | A, B,    D
+;             E        | A, B,    D, E, F
+;                F     | A, B,    D,    F
+;                   G  | A, B,    D,       G
+;
+;
+; ME: define void @complex_loops_and_control
+define void @complex_loops_and_control(i32 %arg, i32 %arg1) {
+bb:
+  call void @A()
+; ME:     call void @A()
+; ME-NOT: mustexec
+; ME-NEXT: br
+; MBEC:      -- Explore context of:   call void @A()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @A()
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb2
+; MBEC-NEXT:   [F: complex_loops_and_control]   %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: br
+  br label %bb2
+
+bb2:                                              ; preds = %.backedge, %bb
+  %.0 = phi i32 [ %arg, %bb ], [ %.0.be, %.backedge ]
+  call void @B()
+; ME: call void @B() ; (mustexec in: bb2)
+; MBEC:      -- Explore context of:   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @B()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp = add nsw i32 %.0, 1
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp3 = icmp eq i32 %tmp, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp3, label %bb4, label %bb5
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: %tmp
+  %tmp = add nsw i32 %.0, 1
+  %tmp3 = icmp eq i32 %tmp, %arg1
+  br i1 %tmp3, label %bb4, label %bb5
+
+bb4:                                              ; preds = %bb2
+  call void @C()
+; ME: call void @C()
+; ME-NOT: mustexec
+; ME-NEXT: br
+; FIXME: Missing A and B (backward)
+; MBEC:      -- Explore context of:   call void @C()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @C()
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb5
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp6 = add nsw i32 %.0, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp7 = icmp eq i32 %tmp6, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp7, label %bb8, label %bb9
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: br
+  br label %bb5
+
+bb5:                                              ; preds = %bb4, %bb2
+  %tmp6 = add nsw i32 %.0, 2
+  %tmp7 = icmp eq i32 %tmp6, %arg1
+  br i1 %tmp7, label %bb8, label %bb9
+
+bb8:                                              ; preds = %bb5
+  br label %.backedge
+
+.backedge:                                        ; preds = %bb8, %bb22
+  %.0.be = phi i32 [ %tmp6, %bb8 ], [ %.lcssa, %bb22 ]
+  br label %bb2
+
+bb9:                                              ; preds = %bb5
+  call void @D()
+; ME: call void @D()
+; ME-NOT: mustexec
+; ME-NEXT: %tmp10
+; FIXME: Missing A and B (backward)
+; MBEC:      -- Explore context of:   call void @D()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @D()
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp10 = add nsw i32 %.0, 3
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp11 = icmp eq i32 %tmp10, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp11, label %bb12, label %bb13
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: %tmp10
+  %tmp10 = add nsw i32 %.0, 3
+  %tmp11 = icmp eq i32 %tmp10, %arg1
+  br i1 %tmp11, label %bb12, label %bb13
+
+bb12:                                             ; preds = %bb9
+  br label %bb23
+
+bb13:                                             ; preds = %bb9
+  br label %bb14
+
+bb14:                                             ; preds = %bb19, %bb13
+  %.1 = phi i32 [ %tmp10, %bb13 ], [ %tmp20, %bb19 ]
+  %tmp15 = add nsw i32 %.1, 1
+  %tmp16 = icmp eq i32 %tmp15, %arg1
+  br i1 %tmp16, label %bb17, label %bb18
+
+bb17:                                             ; preds = %bb14
+  br label %bb19
+
+bb18:                                             ; preds = %bb14
+  call void @E()
+; ME: call void @E()
+; ME-NOT: mustexec
+; ME-NEXT: br
+; FIXME: Missing A, B, and D (backward), as well as F
+; MBEC:      -- Explore context of:   call void @E()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @E()
+; MBEC-NEXT:   [F: complex_loops_and_control]   br label %bb19
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp20 = add nsw i32 %.1, 2
+; MBEC-NEXT:   [F: complex_loops_and_control]   %tmp21 = icmp eq i32 %tmp20, %arg1
+; MBEC-NEXT:   [F: complex_loops_and_control]   br i1 %tmp21, label %bb14, label %bb22
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: br
+  br label %bb19
+
+bb19:                                             ; preds = %bb18, %bb17
+  %tmp20 = add nsw i32 %.1, 2
+  %tmp21 = icmp eq i32 %tmp20, %arg1
+  br i1 %tmp21, label %bb14, label %bb22
+
+bb22:                                             ; preds = %bb19
+  %.lcssa = phi i32 [ %tmp20, %bb19 ]
+  call void @F()
+; ME: call void @F()
+; ME-NOT: mustexec
+; ME-NEXT: br
+; FIXME: Missing A, B, and D (backward)
+; MBEC:      -- Explore context of:   call void @F()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @F()
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: br
+  br label %.backedge
+
+bb23:                                             ; preds = %bb12
+  call void @G()
+; ME: call void @G()
+; ME-NOT: mustexec
+; ME-NEXT: ret
+; FIXME: Missing A, B, and D (backward)
+; MBEC:      -- Explore context of:   call void @G()
+; MBEC-NEXT:   [F: complex_loops_and_control]   call void @G()
+; MBEC-NEXT:   [F: complex_loops_and_control]   ret void
+; MBEC-NOT:    call
+; MBEC:      -- Explore context of: ret
+  ret void
+}
+
+declare void @A() nounwind willreturn
+
+declare void @B() nounwind willreturn
+
+declare void @C() nounwind willreturn
+
+declare void @D() nounwind willreturn
+
+declare void @E() nounwind willreturn
+
+declare void @F() nounwind
+
+declare void @G() nounwind willreturn




More information about the llvm-commits mailing list