<div dir="ltr">Note that the newly added files in this commit used the old header. I've fixed it, but please check any other outstanding patches you have.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Jan 23, 2019 at 2:43 PM Hideki Saito via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: hsaito<br>
Date: Wed Jan 23 14:43:12 2019<br>
New Revision: 351990<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=351990&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=351990&view=rev</a><br>
Log:<br>
<br>
[LV][VPlan] Change to implement VPlan based predication for<br>
VPlan-native path<br>
<br>
Context: Patch Series #2 for outer loop vectorization support in LV<br>
using VPlan. (RFC:<br>
<a href="http://lists.llvm.org/pipermail/llvm-dev/2017-December/119523.html" rel="noreferrer" target="_blank">http://lists.llvm.org/pipermail/llvm-dev/2017-December/119523.html</a>).<br>
<br>
Patch series #2 checks that inner loops are still trivially lock-step<br>
among all vector elements. Non-loop branches are blindly assumed as<br>
divergent.<br>
<br>
Changes here implement VPlan based predication algorithm to compute<br>
predicates for blocks that need predication. Predicates are computed<br>
for the VPLoop region in reverse post order. A block's predicate is<br>
computed as OR of the masks of all incoming edges. The mask for an<br>
incoming edge is computed as AND of predecessor block's predicate and<br>
either predecessor's Condition bit or NOT(Condition bit) depending on<br>
whether the edge from predecessor block to the current block is true<br>
or false edge.<br>
<br>
Reviewers: fhahn, rengolin, hsaito, dcaballe<br>
<br>
Reviewed By: fhahn<br>
<br>
Patch by Satish Guggilla, thanks!<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D53349" rel="noreferrer" target="_blank">https://reviews.llvm.org/D53349</a><br>
<br>
<br>
Added:<br>
    llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp<br>
    llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h<br>
    llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp<br>
Modified:<br>
    llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt<br>
    llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp<br>
    llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp<br>
    llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp<br>
    llvm/trunk/lib/Transforms/Vectorize/VPlan.h<br>
    llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt<br>
<br>
Modified: llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt (original)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/CMakeLists.txt Wed Jan 23 14:43:12 2019<br>
@@ -7,6 +7,7 @@ add_llvm_library(LLVMVectorize<br>
   VPlan.cpp<br>
   VPlanHCFGBuilder.cpp<br>
   VPlanHCFGTransforms.cpp<br>
+  VPlanPredicator.cpp<br>
   VPlanSLP.cpp<br>
   VPlanVerifier.cpp<br>
<br>
<br>
Modified: llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp Wed Jan 23 14:43:12 2019<br>
@@ -22,6 +22,8 @@ using namespace llvm;<br>
 #define LV_NAME "loop-vectorize"<br>
 #define DEBUG_TYPE LV_NAME<br>
<br>
+extern cl::opt<bool> EnableVPlanPredication;<br>
+<br>
 static cl::opt<bool><br>
     EnableIfConversion("enable-if-conversion", cl::init(true), cl::Hidden,<br>
                        cl::desc("Enable if-conversion during vectorization."));<br>
@@ -487,7 +489,10 @@ bool LoopVectorizationLegality::canVecto<br>
     // Check whether the BranchInst is a supported one. Only unconditional<br>
     // branches, conditional branches with an outer loop invariant condition or<br>
     // backedges are supported.<br>
-    if (Br && Br->isConditional() &&<br>
+    // FIXME: We skip these checks when VPlan predication is enabled as we<br>
+    // want to allow divergent branches. This whole check will be removed<br>
+    // once VPlan predication is on by default.<br>
+    if (!EnableVPlanPredication && Br && Br->isConditional() &&<br>
         !TheLoop->isLoopInvariant(Br->getCondition()) &&<br>
         !LI->isLoopHeader(Br->getSuccessor(0)) &&<br>
         !LI->isLoopHeader(Br->getSuccessor(1))) {<br>
<br>
Modified: llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/LoopVectorize.cpp Wed Jan 23 14:43:12 2019<br>
@@ -58,6 +58,7 @@<br>
 #include "VPRecipeBuilder.h"<br>
 #include "VPlanHCFGBuilder.h"<br>
 #include "VPlanHCFGTransforms.h"<br>
+#include "VPlanPredicator.h"<br>
 #include "llvm/ADT/APInt.h"<br>
 #include "llvm/ADT/ArrayRef.h"<br>
 #include "llvm/ADT/DenseMap.h"<br>
@@ -255,6 +256,13 @@ cl::opt<bool> EnableVPlanNativePath(<br>
     cl::desc("Enable VPlan-native vectorization path with "<br>
              "support for outer loop vectorization."));<br>
<br>
+// FIXME: Remove this switch once we have divergence analysis. Currently we<br>
+// assume divergent non-backedge branches when this switch is true.<br>
+cl::opt<bool> EnableVPlanPredication(<br>
+    "enable-vplan-predication", cl::init(false), cl::Hidden,<br>
+    cl::desc("Enable VPlan-native vectorization path predicator with "<br>
+             "support for outer loop vectorization."));<br>
+<br>
 // This flag enables the stress testing of the VPlan H-CFG construction in the<br>
 // VPlan-native vectorization path. It must be used in conjuction with<br>
 // -enable-vplan-native-path. -vplan-verify-hcfg can also be used to enable the<br>
@@ -6896,13 +6904,22 @@ LoopVectorizationPlanner::buildVPlan(VFR<br>
   VPlanHCFGBuilder HCFGBuilder(OrigLoop, LI, *Plan);<br>
   HCFGBuilder.buildHierarchicalCFG();<br>
<br>
+  for (unsigned VF = Range.Start; VF < Range.End; VF *= 2)<br>
+    Plan->addVF(VF);<br>
+<br>
+  if (EnableVPlanPredication) {<br>
+    VPlanPredicator VPP(*Plan);<br>
+    VPP.predicate();<br>
+<br>
+    // Avoid running transformation to recipes until masked code generation in<br>
+    // VPlan-native path is in place.<br>
+    return Plan;<br>
+  }<br>
+<br>
   SmallPtrSet<Instruction *, 1> DeadInstructions;<br>
   VPlanHCFGTransforms::VPInstructionsToVPRecipes(<br>
       Plan, Legal->getInductionVars(), DeadInstructions);<br>
<br>
-  for (unsigned VF = Range.Start; VF < Range.End; VF *= 2)<br>
-    Plan->addVF(VF);<br>
-<br>
   return Plan;<br>
 }<br>
<br>
@@ -7119,8 +7136,8 @@ static bool processLoopInVPlanNativePath<br>
   VectorizationFactor VF = LVP.planInVPlanNativePath(OptForSize, UserVF);<br>
<br>
   // If we are stress testing VPlan builds, do not attempt to generate vector<br>
-  // code.<br>
-  if (VPlanBuildStressTest)<br>
+  // code. Masked vector code generation support will follow soon.<br>
+  if (VPlanBuildStressTest || EnableVPlanPredication)<br>
     return false;<br>
<br>
   LVP.setBestPlan(VF.Width, 1);<br>
<br>
Modified: llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/VPlan.cpp Wed Jan 23 14:43:12 2019<br>
@@ -560,6 +560,19 @@ void VPlanPrinter::dumpBasicBlock(const<br>
   bumpIndent(1);<br>
   OS << Indent << "\"" << DOT::EscapeString(BasicBlock->getName()) << ":\\n\"";<br>
   bumpIndent(1);<br>
+<br>
+  // Dump the block predicate.<br>
+  const VPValue *Pred = BasicBlock->getPredicate();<br>
+  if (Pred) {<br>
+    OS << " +\n" << Indent << " \"BlockPredicate: ";<br>
+    if (const VPInstruction *PredI = dyn_cast<VPInstruction>(Pred)) {<br>
+      PredI->printAsOperand(OS);<br>
+      OS << " (" << DOT::EscapeString(PredI->getParent()->getName())<br>
+         << ")\\l\"";<br>
+    } else<br>
+      Pred->printAsOperand(OS);<br>
+  }<br>
+<br>
   for (const VPRecipeBase &Recipe : *BasicBlock)<br>
     Recipe.print(OS, Indent);<br>
<br>
<br>
Modified: llvm/trunk/lib/Transforms/Vectorize/VPlan.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlan.h?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlan.h?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/VPlan.h (original)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/VPlan.h Wed Jan 23 14:43:12 2019<br>
@@ -352,6 +352,9 @@ private:<br>
   /// Successor selector, null for zero or single successor blocks.<br>
   VPValue *CondBit = nullptr;<br>
<br>
+  /// Current block predicate - null if the block does not need a predicate.<br>
+  VPValue *Predicate = nullptr;<br>
+<br>
   /// Add \p Successor as the last successor to this block.<br>
   void appendSuccessor(VPBlockBase *Successor) {<br>
     assert(Successor && "Cannot add nullptr successor!");<br>
@@ -490,6 +493,12 @@ public:<br>
<br>
   void setCondBit(VPValue *CV) { CondBit = CV; }<br>
<br>
+  VPValue *getPredicate() { return Predicate; }<br>
+<br>
+  const VPValue *getPredicate() const { return Predicate; }<br>
+<br>
+  void setPredicate(VPValue *Pred) { Predicate = Pred; }<br>
+<br>
   /// Set a given VPBlockBase \p Successor as the single successor of this<br>
   /// VPBlockBase. This VPBlockBase is not added as predecessor of \p Successor.<br>
   /// This VPBlockBase must have no successors.<br>
@@ -520,6 +529,15 @@ public:<br>
       appendPredecessor(Pred);<br>
   }<br>
<br>
+  /// Remove all the predecessor of this block.<br>
+  void clearPredecessors() { Predecessors.clear(); }<br>
+<br>
+  /// Remove all the successors of this block and set to null its condition bit<br>
+  void clearSuccessors() {<br>
+    Successors.clear();<br>
+    CondBit = nullptr;<br>
+  }<br>
+<br>
   /// The method which generates the output IR that correspond to this<br>
   /// VPBlockBase, thereby "executing" the VPlan.<br>
   virtual void execute(struct VPTransformState *State) = 0;<br>
@@ -1490,6 +1508,41 @@ public:<br>
     From->removeSuccessor(To);<br>
     To->removePredecessor(From);<br>
   }<br>
+<br>
+  /// Returns true if the edge \p FromBlock -> \p ToBlock is a back-edge.<br>
+  static bool isBackEdge(const VPBlockBase *FromBlock,<br>
+                         const VPBlockBase *ToBlock, const VPLoopInfo *VPLI) {<br>
+    assert(FromBlock->getParent() == ToBlock->getParent() &&<br>
+           FromBlock->getParent() && "Must be in same region");<br>
+    const VPLoop *FromLoop = VPLI->getLoopFor(FromBlock);<br>
+    const VPLoop *ToLoop = VPLI->getLoopFor(ToBlock);<br>
+    if (!FromLoop || !ToLoop || FromLoop != ToLoop)<br>
+      return false;<br>
+<br>
+    // A back-edge is a branch from the loop latch to its header.<br>
+    return ToLoop->isLoopLatch(FromBlock) && ToBlock == ToLoop->getHeader();<br>
+  }<br>
+<br>
+  /// Returns true if \p Block is a loop latch<br>
+  static bool blockIsLoopLatch(const VPBlockBase *Block,<br>
+                               const VPLoopInfo *VPLInfo) {<br>
+    if (const VPLoop *ParentVPL = VPLInfo->getLoopFor(Block))<br>
+      return ParentVPL->isLoopLatch(Block);<br>
+<br>
+    return false;<br>
+  }<br>
+<br>
+  /// Count and return the number of succesors of \p PredBlock excluding any<br>
+  /// backedges.<br>
+  static unsigned countSuccessorsNoBE(VPBlockBase *PredBlock,<br>
+                                      VPLoopInfo *VPLI) {<br>
+    unsigned Count = 0;<br>
+    for (VPBlockBase *SuccBlock : PredBlock->getSuccessors()) {<br>
+      if (!VPBlockUtils::isBackEdge(PredBlock, SuccBlock, VPLI))<br>
+        Count++;<br>
+    }<br>
+    return Count;<br>
+  }<br>
 };<br>
<br>
 class VPInterleavedAccessInfo {<br>
<br>
Added: llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp?rev=351990&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp?rev=351990&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp (added)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.cpp Wed Jan 23 14:43:12 2019<br>
@@ -0,0 +1,249 @@<br>
+//===-- VPlanPredicator.cpp -------------------------------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+///<br>
+/// \file<br>
+/// This file implements the VPlanPredicator class which contains the public<br>
+/// interfaces to predicate and linearize the VPlan region.<br>
+///<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "VPlanPredicator.h"<br>
+#include "VPlan.h"<br>
+#include "llvm/ADT/DepthFirstIterator.h"<br>
+#include "llvm/ADT/GraphTraits.h"<br>
+#include "llvm/ADT/PostOrderIterator.h"<br>
+#include "llvm/Support/Debug.h"<br>
+#include "llvm/Support/raw_ostream.h"<br>
+<br>
+#define DEBUG_TYPE "VPlanPredicator"<br>
+<br>
+using namespace llvm;<br>
+<br>
+// Generate VPInstructions at the beginning of CurrBB that calculate the<br>
+// predicate being propagated from PredBB to CurrBB depending on the edge type<br>
+// between them. For example if:<br>
+//  i.  PredBB is controlled by predicate %BP, and<br>
+//  ii. The edge PredBB->CurrBB is the false edge, controlled by the condition<br>
+//  bit value %CBV then this function will generate the following two<br>
+//  VPInstructions at the start of CurrBB:<br>
+//   %IntermediateVal = not %CBV<br>
+//   %FinalVal        = and %BP %IntermediateVal<br>
+// It returns %FinalVal.<br>
+VPValue *VPlanPredicator::getOrCreateNotPredicate(VPBasicBlock *PredBB,<br>
+                                                  VPBasicBlock *CurrBB) {<br>
+  VPValue *CBV = PredBB->getCondBit();<br>
+<br>
+  // Set the intermediate value - this is either 'CBV', or 'not CBV'<br>
+  // depending on the edge type.<br>
+  EdgeType ET = getEdgeTypeBetween(PredBB, CurrBB);<br>
+  VPValue *IntermediateVal = nullptr;<br>
+  switch (ET) {<br>
+  case EdgeType::TRUE_EDGE:<br>
+    // CurrBB is the true successor of PredBB - nothing to do here.<br>
+    IntermediateVal = CBV;<br>
+    break;<br>
+<br>
+  case EdgeType::FALSE_EDGE:<br>
+    // CurrBB is the False successor of PredBB - compute not of CBV.<br>
+    IntermediateVal = Builder.createNot(CBV);<br>
+    break;<br>
+  }<br>
+<br>
+  // Now AND intermediate value with PredBB's block predicate if it has one.<br>
+  VPValue *BP = PredBB->getPredicate();<br>
+  if (BP)<br>
+    return Builder.createAnd(BP, IntermediateVal);<br>
+  else<br>
+    return IntermediateVal;<br>
+}<br>
+<br>
+// Generate a tree of ORs for all IncomingPredicates in  WorkList.<br>
+// Note: This function destroys the original Worklist.<br>
+//<br>
+// P1 P2 P3 P4 P5<br>
+//  \ /   \ /  /<br>
+//  OR1   OR2 /<br>
+//    \    | /<br>
+//     \   +/-+<br>
+//      \  /  |<br>
+//       OR3  |<br>
+//         \  |<br>
+//          OR4 <- Returns this<br>
+//           |<br>
+//<br>
+// The algorithm uses a worklist of predicates as its main data structure.<br>
+// We pop a pair of values from the front (e.g. P1 and P2), generate an OR<br>
+// (in this example OR1), and push it back. In this example the worklist<br>
+// contains {P3, P4, P5, OR1}.<br>
+// The process iterates until we have only one element in the Worklist (OR4).<br>
+// The last element is the root predicate which is returned.<br>
+VPValue *VPlanPredicator::genPredicateTree(std::list<VPValue *> &Worklist) {<br>
+  if (Worklist.empty())<br>
+    return nullptr;<br>
+<br>
+  // The worklist initially contains all the leaf nodes. Initialize the tree<br>
+  // using them.<br>
+  while (Worklist.size() >= 2) {<br>
+    // Pop a pair of values from the front.<br>
+    VPValue *LHS = Worklist.front();<br>
+    Worklist.pop_front();<br>
+    VPValue *RHS = Worklist.front();<br>
+    Worklist.pop_front();<br>
+<br>
+    // Create an OR of these values.<br>
+    VPValue *Or = Builder.createOr(LHS, RHS);<br>
+<br>
+    // Push OR to the back of the worklist.<br>
+    Worklist.push_back(Or);<br>
+  }<br>
+<br>
+  assert(Worklist.size() == 1 && "Expected 1 item in worklist");<br>
+<br>
+  // The root is the last node in the worklist.<br>
+  VPValue *Root = Worklist.front();<br>
+<br>
+  // This root needs to replace the existing block predicate. This is done in<br>
+  // the caller function.<br>
+  return Root;<br>
+}<br>
+<br>
+// Return whether the edge FromBlock -> ToBlock is a TRUE_EDGE or FALSE_EDGE<br>
+VPlanPredicator::EdgeType<br>
+VPlanPredicator::getEdgeTypeBetween(VPBlockBase *FromBlock,<br>
+                                    VPBlockBase *ToBlock) {<br>
+  unsigned Count = 0;<br>
+  for (VPBlockBase *SuccBlock : FromBlock->getSuccessors()) {<br>
+    if (SuccBlock == ToBlock) {<br>
+      assert(Count < 2 && "Switch not supported currently");<br>
+      return (Count == 0) ? EdgeType::TRUE_EDGE : EdgeType::FALSE_EDGE;<br>
+    }<br>
+    Count++;<br>
+  }<br>
+<br>
+  llvm_unreachable("Broken getEdgeTypeBetween");<br>
+}<br>
+<br>
+// Generate all predicates needed for CurrBlock by going through its immediate<br>
+// predecessor blocks.<br>
+void VPlanPredicator::createOrPropagatePredicates(VPBlockBase *CurrBlock,<br>
+                                                  VPRegionBlock *Region) {<br>
+  // Blocks that dominate region exit inherit the predicate from the region.<br>
+  // Return after setting the predicate.<br>
+  if (VPDomTree.dominates(CurrBlock, Region->getExit())) {<br>
+    VPValue *RegionBP = Region->getPredicate();<br>
+    CurrBlock->setPredicate(RegionBP);<br>
+    return;<br>
+  }<br>
+<br>
+  // Collect all incoming predicates in a worklist.<br>
+  std::list<VPValue *> IncomingPredicates;<br>
+<br>
+  // Set the builder's insertion point to the top of the current BB<br>
+  VPBasicBlock *CurrBB = cast<VPBasicBlock>(CurrBlock->getEntryBasicBlock());<br>
+  Builder.setInsertPoint(CurrBB, CurrBB->begin());<br>
+<br>
+  // For each predecessor, generate the VPInstructions required for<br>
+  // computing 'BP AND (not) CBV" at the top of CurrBB.<br>
+  // Collect the outcome of this calculation for all predecessors<br>
+  // into IncomingPredicates.<br>
+  for (VPBlockBase *PredBlock : CurrBlock->getPredecessors()) {<br>
+    // Skip back-edges<br>
+    if (VPBlockUtils::isBackEdge(PredBlock, CurrBlock, VPLI))<br>
+      continue;<br>
+<br>
+    VPValue *IncomingPredicate = nullptr;<br>
+    unsigned NumPredSuccsNoBE =<br>
+        VPBlockUtils::countSuccessorsNoBE(PredBlock, VPLI);<br>
+<br>
+    // If there is an unconditional branch to the currBB, then we don't create<br>
+    // edge predicates. We use the predecessor's block predicate instead.<br>
+    if (NumPredSuccsNoBE == 1)<br>
+      IncomingPredicate = PredBlock->getPredicate();<br>
+    else if (NumPredSuccsNoBE == 2) {<br>
+      // Emit recipes into CurrBlock if required<br>
+      assert(isa<VPBasicBlock>(PredBlock) && "Only BBs have multiple exits");<br>
+      IncomingPredicate =<br>
+          getOrCreateNotPredicate(cast<VPBasicBlock>(PredBlock), CurrBB);<br>
+    } else<br>
+      llvm_unreachable("FIXME: switch statement ?");<br>
+<br>
+    if (IncomingPredicate)<br>
+      IncomingPredicates.push_back(IncomingPredicate);<br>
+  }<br>
+<br>
+  // Logically OR all incoming predicates by building the Predicate Tree.<br>
+  VPValue *Predicate = genPredicateTree(IncomingPredicates);<br>
+<br>
+  // Now update the block's predicate with the new one.<br>
+  CurrBlock->setPredicate(Predicate);<br>
+}<br>
+<br>
+// Generate all predicates needed for Region.<br>
+void VPlanPredicator::predicateRegionRec(VPRegionBlock *Region) {<br>
+  VPBasicBlock *EntryBlock = cast<VPBasicBlock>(Region->getEntry());<br>
+  ReversePostOrderTraversal<VPBlockBase *> RPOT(EntryBlock);<br>
+<br>
+  // Generate edge predicates and append them to the block predicate. RPO is<br>
+  // necessary since the predecessor blocks' block predicate needs to be set<br>
+  // before the current block's block predicate can be computed.<br>
+  for (VPBlockBase *Block : make_range(RPOT.begin(), RPOT.end())) {<br>
+    // TODO: Handle nested regions once we start generating the same.<br>
+    assert(!isa<VPRegionBlock>(Block) && "Nested region not expected");<br>
+    createOrPropagatePredicates(Block, Region);<br>
+  }<br>
+}<br>
+<br>
+// Linearize the CFG within Region.<br>
+// TODO: Predication and linearization need RPOT for every region.<br>
+// This traversal is expensive. Since predication is not adding new<br>
+// blocks, we should be able to compute RPOT once in predication and<br>
+// reuse it here. This becomes even more important once we have nested<br>
+// regions.<br>
+void VPlanPredicator::linearizeRegionRec(VPRegionBlock *Region) {<br>
+  ReversePostOrderTraversal<VPBlockBase *> RPOT(Region->getEntry());<br>
+  VPBlockBase *PrevBlock = nullptr;<br>
+<br>
+  for (VPBlockBase *CurrBlock : make_range(RPOT.begin(), RPOT.end())) {<br>
+    // TODO: Handle nested regions once we start generating the same.<br>
+    assert(!isa<VPRegionBlock>(CurrBlock) && "Nested region not expected");<br>
+<br>
+    // Linearize control flow by adding an unconditional edge between PrevBlock<br>
+    // and CurrBlock skipping loop headers and latches to keep intact loop<br>
+    // header predecessors and loop latch successors.<br>
+    if (PrevBlock && !VPLI->isLoopHeader(CurrBlock) &&<br>
+        !VPBlockUtils::blockIsLoopLatch(PrevBlock, VPLI)) {<br>
+<br>
+      LLVM_DEBUG(dbgs() << "Linearizing: " << PrevBlock->getName() << "->"<br>
+                        << CurrBlock->getName() << "\n");<br>
+<br>
+      PrevBlock->clearSuccessors();<br>
+      CurrBlock->clearPredecessors();<br>
+      VPBlockUtils::connectBlocks(PrevBlock, CurrBlock);<br>
+    }<br>
+<br>
+    PrevBlock = CurrBlock;<br>
+  }<br>
+}<br>
+<br>
+// Entry point. The driver function for the predicator.<br>
+void VPlanPredicator::predicate(void) {<br>
+  // Predicate the blocks within Region.<br>
+  predicateRegionRec(cast<VPRegionBlock>(Plan.getEntry()));<br>
+<br>
+  // Linearlize the blocks with Region.<br>
+  linearizeRegionRec(cast<VPRegionBlock>(Plan.getEntry()));<br>
+}<br>
+<br>
+VPlanPredicator::VPlanPredicator(VPlan &Plan)<br>
+    : Plan(Plan), VPLI(&(Plan.getVPLoopInfo())) {<br>
+  // FIXME: Predicator is currently computing the dominator information for the<br>
+  // top region. Once we start storing dominator information in a VPRegionBlock,<br>
+  // we can avoid this recalculation.<br>
+  VPDomTree.recalculate(*(cast<VPRegionBlock>(Plan.getEntry())));<br>
+}<br>
<br>
Added: llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h?rev=351990&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h?rev=351990&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h (added)<br>
+++ llvm/trunk/lib/Transforms/Vectorize/VPlanPredicator.h Wed Jan 23 14:43:12 2019<br>
@@ -0,0 +1,75 @@<br>
+//===-- VPlanPredicator.h ---------------------------------------*- C++ -*-===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+///<br>
+/// \file<br>
+/// This file defines the VPlanPredicator class which contains the public<br>
+/// interfaces to predicate and linearize the VPlan region.<br>
+///<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLAN_PREDICATOR_H<br>
+#define LLVM_TRANSFORMS_VECTORIZE_VPLAN_PREDICATOR_H<br>
+<br>
+#include "LoopVectorizationPlanner.h"<br>
+#include "VPlan.h"<br>
+#include "VPlanDominatorTree.h"<br>
+<br>
+namespace llvm {<br>
+<br>
+class VPlanPredicator {<br>
+private:<br>
+  enum class EdgeType {<br>
+    TRUE_EDGE,<br>
+    FALSE_EDGE,<br>
+  };<br>
+<br>
+  // VPlan being predicated.<br>
+  VPlan &Plan;<br>
+<br>
+  // VPLoopInfo for Plan's HCFG.<br>
+  VPLoopInfo *VPLI;<br>
+<br>
+  // Dominator tree for Plan's HCFG.<br>
+  VPDominatorTree VPDomTree;<br>
+<br>
+  // VPlan builder used to generate VPInstructions for block predicates.<br>
+  VPBuilder Builder;<br>
+<br>
+  /// Get the type of edge from \p FromBlock to \p ToBlock. Returns TRUE_EDGE if<br>
+  /// \p ToBlock is either the unconditional successor or the conditional true<br>
+  /// successor of \p FromBlock and FALSE_EDGE otherwise.<br>
+  EdgeType getEdgeTypeBetween(VPBlockBase *FromBlock, VPBlockBase *ToBlock);<br>
+<br>
+  /// Create and return VPValue corresponding to the predicate for the edge from<br>
+  /// \p PredBB to \p CurrentBlock.<br>
+  VPValue *getOrCreateNotPredicate(VPBasicBlock *PredBB, VPBasicBlock *CurrBB);<br>
+<br>
+  /// Generate and return the result of ORing all the predicate VPValues in \p<br>
+  /// Worklist.<br>
+  VPValue *genPredicateTree(std::list<VPValue *> &Worklist);<br>
+<br>
+  /// Create or propagate predicate for \p CurrBlock in region \p Region using<br>
+  /// predicate(s) of its predecessor(s)<br>
+  void createOrPropagatePredicates(VPBlockBase *CurrBlock,<br>
+                                   VPRegionBlock *Region);<br>
+<br>
+  /// Predicate the CFG within \p Region.<br>
+  void predicateRegionRec(VPRegionBlock *Region);<br>
+<br>
+  /// Linearize the CFG within \p Region.<br>
+  void linearizeRegionRec(VPRegionBlock *Region);<br>
+<br>
+public:<br>
+  VPlanPredicator(VPlan &Plan);<br>
+<br>
+  /// Predicate Plan's HCFG.<br>
+  void predicate(void);<br>
+};<br>
+} // end namespace llvm<br>
+#endif // LLVM_TRANSFORMS_VECTORIZE_VPLAN_PREDICATOR_H<br>
<br>
Modified: llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt?rev=351990&r1=351989&r2=351990&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt?rev=351990&r1=351989&r2=351990&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt (original)<br>
+++ llvm/trunk/unittests/Transforms/Vectorize/CMakeLists.txt Wed Jan 23 14:43:12 2019<br>
@@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS<br>
 add_llvm_unittest(VectorizeTests<br>
   VPlanDominatorTreeTest.cpp<br>
   VPlanLoopInfoTest.cpp<br>
+  VPlanPredicatorTest.cpp<br>
   VPlanTest.cpp<br>
   VPlanHCFGTest.cpp<br>
   VPlanSlpTest.cpp<br>
<br>
Added: llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp?rev=351990&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp?rev=351990&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp (added)<br>
+++ llvm/trunk/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp Wed Jan 23 14:43:12 2019<br>
@@ -0,0 +1,230 @@<br>
+//===- llvm/unittests/Transforms/Vectorize/VPlanPredicatorTest.cpp -----===//<br>
+//<br>
+//                     The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "../lib/Transforms/Vectorize/VPlanPredicator.h"<br>
+#include "VPlanTestBase.h"<br>
+#include "gtest/gtest.h"<br>
+<br>
+namespace llvm {<br>
+namespace {<br>
+<br>
+class VPlanPredicatorTest : public VPlanTestBase {};<br>
+<br>
+TEST_F(VPlanPredicatorTest, BasicPredicatorTest) {<br>
+  const char *ModuleString =<br>
+      "@arr = common global [8 x [8 x i64]] "<br>
+      "zeroinitializer, align 16\n"<br>
+      "@arr2 = common global [8 x [8 x i64]] "<br>
+      "zeroinitializer, align 16\n"<br>
+      "@arr3 = common global [8 x [8 x i64]] "<br>
+      "zeroinitializer, align 16\n"<br>
+      "define void @f(i64 %n1) {\n"<br>
+      "entry:\n"<br>
+      "  br label %for.cond1.preheader\n"<br>
+      "for.cond1.preheader:                              \n"<br>
+      "  %i1.029 = phi i64 [ 0, %entry ], [ %inc14, %for.inc13 ]\n"<br>
+      "  br label %for.body3\n"<br>
+      "for.body3:                                        \n"<br>
+      "  %i2.028 = phi i64 [ 0, %for.cond1.preheader ], [ %inc, %for.inc ]\n"<br>
+      "  %arrayidx4 = getelementptr inbounds [8 x [8 x i64]], [8 x [8 x i64]]* "<br>
+      "@arr, i64 0, i64 %i2.028, i64 %i1.029\n"<br>
+      "  %0 = load i64, i64* %arrayidx4, align 8\n"<br>
+      "  %cmp5 = icmp ugt i64 %0, 10\n"<br>
+      "  br i1 %cmp5, label %if.then, label %for.inc\n"<br>
+      "if.then:                                          \n"<br>
+      "  %arrayidx7 = getelementptr inbounds [8 x [8 x i64]], [8 x [8 x i64]]* "<br>
+      "@arr2, i64 0, i64 %i2.028, i64 %i1.029\n"<br>
+      "  %1 = load i64, i64* %arrayidx7, align 8\n"<br>
+      "  %cmp8 = icmp ugt i64 %1, 100\n"<br>
+      "  br i1 %cmp8, label %if.then9, label %for.inc\n"<br>
+      "if.then9:                                         \n"<br>
+      "  %add = add nuw nsw i64 %i2.028, %i1.029\n"<br>
+      "  %arrayidx11 = getelementptr inbounds [8 x [8 x i64]], [8 x [8 x "<br>
+      "i64]]* @arr3, i64 0, i64 %i2.028, i64 %i1.029\n"<br>
+      "  store i64 %add, i64* %arrayidx11, align 8\n"<br>
+      "  br label %for.inc\n"<br>
+      "for.inc:                                          \n"<br>
+      "  %inc = add nuw nsw i64 %i2.028, 1\n"<br>
+      "  %exitcond = icmp eq i64 %inc, 8\n"<br>
+      "  br i1 %exitcond, label %for.inc13, label %for.body3\n"<br>
+      "for.inc13:                                        \n"<br>
+      "  %inc14 = add nuw nsw i64 %i1.029, 1\n"<br>
+      "  %exitcond30 = icmp eq i64 %inc14, 8\n"<br>
+      "  br i1 %exitcond30, label %for.end15, label %for.cond1.preheader\n"<br>
+      "for.end15:                                        \n"<br>
+      "  ret void\n"<br>
+      "}\n";<br>
+<br>
+  Module &M = parseModule(ModuleString);<br>
+<br>
+  Function *F = M.getFunction("f");<br>
+  BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();<br>
+  auto Plan = buildHCFG(LoopHeader);<br>
+<br>
+  VPRegionBlock *TopRegion = cast<VPRegionBlock>(Plan->getEntry());<br>
+  VPBlockBase *PH = TopRegion->getEntry();<br>
+  VPBlockBase *H = PH->getSingleSuccessor();<br>
+  VPBlockBase *InnerLoopH = H->getSingleSuccessor();<br>
+  VPBlockBase *OuterIf = InnerLoopH->getSuccessors()[0];<br>
+  VPBlockBase *InnerLoopLatch = InnerLoopH->getSuccessors()[1];<br>
+  VPBlockBase *InnerIf = OuterIf->getSuccessors()[0];<br>
+  VPValue *CBV1 = InnerLoopH->getCondBit();<br>
+  VPValue *CBV2 = OuterIf->getCondBit();<br>
+<br>
+  // Apply predication.<br>
+  VPlanPredicator VPP(*Plan);<br>
+  VPP.predicate();<br>
+<br>
+  VPBlockBase *InnerLoopLinSucc = InnerLoopH->getSingleSuccessor();<br>
+  VPBlockBase *OuterIfLinSucc = OuterIf->getSingleSuccessor();<br>
+  VPBlockBase *InnerIfLinSucc = InnerIf->getSingleSuccessor();<br>
+  VPValue *OuterIfPred = OuterIf->getPredicate();<br>
+  VPInstruction *InnerAnd =<br>
+      cast<VPInstruction>(InnerIf->getEntryBasicBlock()->begin());<br>
+  VPValue *InnerIfPred = InnerIf->getPredicate();<br>
+<br>
+  // Test block predicates<br>
+  EXPECT_NE(nullptr, CBV1);<br>
+  EXPECT_NE(nullptr, CBV2);<br>
+  EXPECT_NE(nullptr, InnerAnd);<br>
+  EXPECT_EQ(CBV1, OuterIfPred);<br>
+  EXPECT_EQ(InnerAnd->getOpcode(), Instruction::And);<br>
+  EXPECT_EQ(InnerAnd->getOperand(0), CBV1);<br>
+  EXPECT_EQ(InnerAnd->getOperand(1), CBV2);<br>
+  EXPECT_EQ(InnerIfPred, InnerAnd);<br>
+<br>
+  // Test Linearization<br>
+  EXPECT_EQ(InnerLoopLinSucc, OuterIf);<br>
+  EXPECT_EQ(OuterIfLinSucc, InnerIf);<br>
+  EXPECT_EQ(InnerIfLinSucc, InnerLoopLatch);<br>
+}<br>
+<br>
+// Test generation of Not and Or during predication.<br>
+TEST_F(VPlanPredicatorTest, PredicatorNegOrTest) {<br>
+  const char *ModuleString =<br>
+      "@arr = common global [100 x [100 x i32]] zeroinitializer, align 16\n"<br>
+      "@arr2 = common global [100 x [100 x i32]] zeroinitializer, align 16\n"<br>
+      "@arr3 = common global [100 x [100 x i32]] zeroinitializer, align 16\n"<br>
+      "define void @foo() {\n"<br>
+      "entry:\n"<br>
+      "  br label %for.cond1.preheader\n"<br>
+      "for.cond1.preheader:                              \n"<br>
+      "  %indvars.iv42 = phi i64 [ 0, %entry ], [ %indvars.iv.next43, "<br>
+      "%for.inc22 ]\n"<br>
+      "  br label %for.body3\n"<br>
+      "for.body3:                                        \n"<br>
+      "  %indvars.iv = phi i64 [ 0, %for.cond1.preheader ], [ "<br>
+      "%indvars.iv.next, %if.end21 ]\n"<br>
+      "  %arrayidx5 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 "<br>
+      "x i32]]* @arr, i64 0, i64 %indvars.iv, i64 %indvars.iv42\n"<br>
+      "  %0 = load i32, i32* %arrayidx5, align 4\n"<br>
+      "  %cmp6 = icmp slt i32 %0, 100\n"<br>
+      "  br i1 %cmp6, label %if.then, label %if.end21\n"<br>
+      "if.then:                                          \n"<br>
+      "  %cmp7 = icmp sgt i32 %0, 10\n"<br>
+      "  br i1 %cmp7, label %if.then8, label %if.else\n"<br>
+      "if.then8:                                         \n"<br>
+      "  %add = add nsw i32 %0, 10\n"<br>
+      "  %arrayidx12 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 "<br>
+      "x i32]]* @arr2, i64 0, i64 %indvars.iv, i64 %indvars.iv42\n"<br>
+      "  store i32 %add, i32* %arrayidx12, align 4\n"<br>
+      "  br label %if.end\n"<br>
+      "if.else:                                          \n"<br>
+      "  %sub = add nsw i32 %0, -10\n"<br>
+      "  %arrayidx16 = getelementptr inbounds [100 x [100 x i32]], [100 x [100 "<br>
+      "x i32]]* @arr3, i64 0, i64 %indvars.iv, i64 %indvars.iv42\n"<br>
+      "  store i32 %sub, i32* %arrayidx16, align 4\n"<br>
+      "  br label %if.end\n"<br>
+      "if.end:                                           \n"<br>
+      "  store i32 222, i32* %arrayidx5, align 4\n"<br>
+      "  br label %if.end21\n"<br>
+      "if.end21:                                         \n"<br>
+      "  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1\n"<br>
+      "  %exitcond = icmp eq i64 %indvars.iv.next, 100\n"<br>
+      "  br i1 %exitcond, label %for.inc22, label %for.body3\n"<br>
+      "for.inc22:                                        \n"<br>
+      "  %indvars.iv.next43 = add nuw nsw i64 %indvars.iv42, 1\n"<br>
+      "  %exitcond44 = icmp eq i64 %indvars.iv.next43, 100\n"<br>
+      "  br i1 %exitcond44, label %for.end24, label %for.cond1.preheader\n"<br>
+      "for.end24:                                        \n"<br>
+      "  ret void\n"<br>
+      "}\n";<br>
+<br>
+  Module &M = parseModule(ModuleString);<br>
+  Function *F = M.getFunction("foo");<br>
+  BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();<br>
+  auto Plan = buildHCFG(LoopHeader);<br>
+<br>
+  VPRegionBlock *TopRegion = cast<VPRegionBlock>(Plan->getEntry());<br>
+  VPBlockBase *PH = TopRegion->getEntry();<br>
+  VPBlockBase *H = PH->getSingleSuccessor();<br>
+  VPBlockBase *OuterIfCmpBlk = H->getSingleSuccessor();<br>
+  VPBlockBase *InnerIfCmpBlk = OuterIfCmpBlk->getSuccessors()[0];<br>
+  VPBlockBase *InnerIfTSucc = InnerIfCmpBlk->getSuccessors()[0];<br>
+  VPBlockBase *InnerIfFSucc = InnerIfCmpBlk->getSuccessors()[1];<br>
+  VPBlockBase *TSuccSucc = InnerIfTSucc->getSingleSuccessor();<br>
+  VPBlockBase *FSuccSucc = InnerIfFSucc->getSingleSuccessor();<br>
+<br>
+  VPValue *OuterCBV = OuterIfCmpBlk->getCondBit();<br>
+  VPValue *InnerCBV = InnerIfCmpBlk->getCondBit();<br>
+<br>
+  // Apply predication.<br>
+  VPlanPredicator VPP(*Plan);<br>
+  VPP.predicate();<br>
+<br>
+  VPInstruction *And =<br>
+      cast<VPInstruction>(InnerIfTSucc->getEntryBasicBlock()->begin());<br>
+  VPInstruction *Not =<br>
+      cast<VPInstruction>(InnerIfFSucc->getEntryBasicBlock()->begin());<br>
+  VPInstruction *NotAnd = cast<VPInstruction>(<br>
+      &*std::next(InnerIfFSucc->getEntryBasicBlock()->begin(), 1));<br>
+  VPInstruction *Or =<br>
+      cast<VPInstruction>(TSuccSucc->getEntryBasicBlock()->begin());<br>
+<br>
+  // Test block predicates<br>
+  EXPECT_NE(nullptr, OuterCBV);<br>
+  EXPECT_NE(nullptr, InnerCBV);<br>
+  EXPECT_NE(nullptr, And);<br>
+  EXPECT_NE(nullptr, Not);<br>
+  EXPECT_NE(nullptr, NotAnd);<br>
+<br>
+  EXPECT_EQ(And->getOpcode(), Instruction::And);<br>
+  EXPECT_EQ(NotAnd->getOpcode(), Instruction::And);<br>
+  EXPECT_EQ(Not->getOpcode(), VPInstruction::Not);<br>
+<br>
+  EXPECT_EQ(And->getOperand(0), OuterCBV);<br>
+  EXPECT_EQ(And->getOperand(1), InnerCBV);<br>
+<br>
+  EXPECT_EQ(Not->getOperand(0), InnerCBV);<br>
+<br>
+  EXPECT_EQ(NotAnd->getOperand(0), OuterCBV);<br>
+  EXPECT_EQ(NotAnd->getOperand(1), Not);<br>
+<br>
+  EXPECT_EQ(InnerIfTSucc->getPredicate(), And);<br>
+  EXPECT_EQ(InnerIfFSucc->getPredicate(), NotAnd);<br>
+<br>
+  EXPECT_EQ(TSuccSucc, FSuccSucc);<br>
+  EXPECT_EQ(Or->getOpcode(), Instruction::Or);<br>
+  EXPECT_EQ(TSuccSucc->getPredicate(), Or);<br>
+<br>
+  // Test operands of the Or - account for differences in predecessor block<br>
+  // ordering.<br>
+  VPInstruction *OrOp0Inst = cast<VPInstruction>(Or->getOperand(0));<br>
+  VPInstruction *OrOp1Inst = cast<VPInstruction>(Or->getOperand(1));<br>
+<br>
+  bool ValidOrOperands = false;<br>
+  if (((OrOp0Inst == And) && (OrOp1Inst == NotAnd)) ||<br>
+      ((OrOp0Inst == NotAnd) && (OrOp1Inst == And)))<br>
+    ValidOrOperands = true;<br>
+<br>
+  EXPECT_TRUE(ValidOrOperands);<br>
+}<br>
+<br>
+} // namespace<br>
+} // namespace llvm<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div>