[llvm] r249211 - [SCEV] Recognize simple br-phi patterns

Sanjoy Das via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 2 16:09:44 PDT 2015


Author: sanjoy
Date: Fri Oct  2 18:09:44 2015
New Revision: 249211

URL: http://llvm.org/viewvc/llvm-project?rev=249211&view=rev
Log:
[SCEV] Recognize simple br-phi patterns

Summary:
Teach SCEV to match patterns like

```
  br %cond, label %left, label %right
 left:
  br label %merge
 right:
  br label %merge
 merge:
  V = phi [ %x, %left ], [ %y, %right ]
```

as "select %cond, %x, %y".  Before this SCEV would match PHI nodes
exclusively to add recurrences.

This addresses PR25005.

Reviewers: joker.eph, joker-eph, atrick

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D13378

Added:
    llvm/trunk/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll
Modified:
    llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
    llvm/trunk/lib/Analysis/ScalarEvolution.cpp

Modified: llvm/trunk/include/llvm/Analysis/ScalarEvolution.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ScalarEvolution.h?rev=249211&r1=249210&r2=249211&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ScalarEvolution.h (original)
+++ llvm/trunk/include/llvm/Analysis/ScalarEvolution.h Fri Oct  2 18:09:44 2015
@@ -415,12 +415,18 @@ namespace llvm {
     /// Provide the special handling we need to analyze PHI SCEVs.
     const SCEV *createNodeForPHI(PHINode *PN);
 
+    /// Helper function called from createNodeForPHI.
+    const SCEV *createAddRecFromPHI(PHINode *PN);
+
+    /// Helper function called from createNodeForPHI.
+    const SCEV *createNodeFromSelectLikePHI(PHINode *PN);
+
     /// Provide special handling for a select-like instruction (currently this
     /// is either a select instruction or a phi node).  \p I is the instruction
     /// being processed, and it is assumed equivalent to "Cond ? TrueVal :
     /// FalseVal".
-    const SCEV *createNodeForSelect(Instruction *I, Value *Cond, Value *TrueVal,
-                                    Value *FalseVal);
+    const SCEV *createNodeForSelectOrPHI(Instruction *I, Value *Cond,
+                                         Value *TrueVal, Value *FalseVal);
 
     /// Provide the special handling we need to analyze GEP SCEVs.
     const SCEV *createNodeForGEP(GEPOperator *GEP);

Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=249211&r1=249210&r2=249211&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
+++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Fri Oct  2 18:09:44 2015
@@ -3597,151 +3597,293 @@ ScalarEvolution::ForgetSymbolicName(Inst
   }
 }
 
-/// createNodeForPHI - PHI nodes have two cases.  Either the PHI node exists in
-/// a loop header, making it a potential recurrence, or it doesn't.
-///
-const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) {
-  if (const Loop *L = LI.getLoopFor(PN->getParent()))
-    if (L->getHeader() == PN->getParent()) {
-      // The loop may have multiple entrances or multiple exits; we can analyze
-      // this phi as an addrec if it has a unique entry value and a unique
-      // backedge value.
-      Value *BEValueV = nullptr, *StartValueV = nullptr;
-      for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
-        Value *V = PN->getIncomingValue(i);
-        if (L->contains(PN->getIncomingBlock(i))) {
-          if (!BEValueV) {
-            BEValueV = V;
-          } else if (BEValueV != V) {
-            BEValueV = nullptr;
+const SCEV *ScalarEvolution::createAddRecFromPHI(PHINode *PN) {
+  const Loop *L = LI.getLoopFor(PN->getParent());
+  if (!L || L->getHeader() != PN->getParent())
+    return nullptr;
+
+  // The loop may have multiple entrances or multiple exits; we can analyze
+  // this phi as an addrec if it has a unique entry value and a unique
+  // backedge value.
+  Value *BEValueV = nullptr, *StartValueV = nullptr;
+  for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) {
+    Value *V = PN->getIncomingValue(i);
+    if (L->contains(PN->getIncomingBlock(i))) {
+      if (!BEValueV) {
+        BEValueV = V;
+      } else if (BEValueV != V) {
+        BEValueV = nullptr;
+        break;
+      }
+    } else if (!StartValueV) {
+      StartValueV = V;
+    } else if (StartValueV != V) {
+      StartValueV = nullptr;
+      break;
+    }
+  }
+  if (BEValueV && StartValueV) {
+    // While we are analyzing this PHI node, handle its value symbolically.
+    const SCEV *SymbolicName = getUnknown(PN);
+    assert(ValueExprMap.find_as(PN) == ValueExprMap.end() &&
+           "PHI node already processed?");
+    ValueExprMap.insert(std::make_pair(SCEVCallbackVH(PN, this), SymbolicName));
+
+    // Using this symbolic name for the PHI, analyze the value coming around
+    // the back-edge.
+    const SCEV *BEValue = getSCEV(BEValueV);
+
+    // NOTE: If BEValue is loop invariant, we know that the PHI node just
+    // has a special value for the first iteration of the loop.
+
+    // If the value coming around the backedge is an add with the symbolic
+    // value we just inserted, then we found a simple induction variable!
+    if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(BEValue)) {
+      // If there is a single occurrence of the symbolic value, replace it
+      // with a recurrence.
+      unsigned FoundIndex = Add->getNumOperands();
+      for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
+        if (Add->getOperand(i) == SymbolicName)
+          if (FoundIndex == e) {
+            FoundIndex = i;
             break;
           }
-        } else if (!StartValueV) {
-          StartValueV = V;
-        } else if (StartValueV != V) {
-          StartValueV = nullptr;
-          break;
-        }
-      }
-      if (BEValueV && StartValueV) {
-        // While we are analyzing this PHI node, handle its value symbolically.
-        const SCEV *SymbolicName = getUnknown(PN);
-        assert(ValueExprMap.find_as(PN) == ValueExprMap.end() &&
-               "PHI node already processed?");
-        ValueExprMap.insert(std::make_pair(SCEVCallbackVH(PN, this), SymbolicName));
-
-        // Using this symbolic name for the PHI, analyze the value coming around
-        // the back-edge.
-        const SCEV *BEValue = getSCEV(BEValueV);
-
-        // NOTE: If BEValue is loop invariant, we know that the PHI node just
-        // has a special value for the first iteration of the loop.
-
-        // If the value coming around the backedge is an add with the symbolic
-        // value we just inserted, then we found a simple induction variable!
-        if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(BEValue)) {
-          // If there is a single occurrence of the symbolic value, replace it
-          // with a recurrence.
-          unsigned FoundIndex = Add->getNumOperands();
-          for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
-            if (Add->getOperand(i) == SymbolicName)
-              if (FoundIndex == e) {
-                FoundIndex = i;
-                break;
-              }
-
-          if (FoundIndex != Add->getNumOperands()) {
-            // Create an add with everything but the specified operand.
-            SmallVector<const SCEV *, 8> Ops;
-            for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
-              if (i != FoundIndex)
-                Ops.push_back(Add->getOperand(i));
-            const SCEV *Accum = getAddExpr(Ops);
-
-            // This is not a valid addrec if the step amount is varying each
-            // loop iteration, but is not itself an addrec in this loop.
-            if (isLoopInvariant(Accum, L) ||
-                (isa<SCEVAddRecExpr>(Accum) &&
-                 cast<SCEVAddRecExpr>(Accum)->getLoop() == L)) {
-              SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
-
-              // If the increment doesn't overflow, then neither the addrec nor
-              // the post-increment will overflow.
-              if (const AddOperator *OBO = dyn_cast<AddOperator>(BEValueV)) {
-                if (OBO->getOperand(0) == PN) {
-                  if (OBO->hasNoUnsignedWrap())
-                    Flags = setFlags(Flags, SCEV::FlagNUW);
-                  if (OBO->hasNoSignedWrap())
-                    Flags = setFlags(Flags, SCEV::FlagNSW);
-                }
-              } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(BEValueV)) {
-                // If the increment is an inbounds GEP, then we know the address
-                // space cannot be wrapped around. We cannot make any guarantee
-                // about signed or unsigned overflow because pointers are
-                // unsigned but we may have a negative index from the base
-                // pointer. We can guarantee that no unsigned wrap occurs if the
-                // indices form a positive value.
-                if (GEP->isInBounds() && GEP->getOperand(0) == PN) {
-                  Flags = setFlags(Flags, SCEV::FlagNW);
-
-                  const SCEV *Ptr = getSCEV(GEP->getPointerOperand());
-                  if (isKnownPositive(getMinusSCEV(getSCEV(GEP), Ptr)))
-                    Flags = setFlags(Flags, SCEV::FlagNUW);
-                }
-
-                // We cannot transfer nuw and nsw flags from subtraction
-                // operations -- sub nuw X, Y is not the same as add nuw X, -Y
-                // for instance.
-              }
-
-              const SCEV *StartVal = getSCEV(StartValueV);
-              const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
-
-              // Since the no-wrap flags are on the increment, they apply to the
-              // post-incremented value as well.
-              if (isLoopInvariant(Accum, L))
-                (void)getAddRecExpr(getAddExpr(StartVal, Accum),
-                                    Accum, L, Flags);
-
-              // Okay, for the entire analysis of this edge we assumed the PHI
-              // to be symbolic.  We now need to go back and purge all of the
-              // entries for the scalars that use the symbolic expression.
-              ForgetSymbolicName(PN, SymbolicName);
-              ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV;
-              return PHISCEV;
+
+      if (FoundIndex != Add->getNumOperands()) {
+        // Create an add with everything but the specified operand.
+        SmallVector<const SCEV *, 8> Ops;
+        for (unsigned i = 0, e = Add->getNumOperands(); i != e; ++i)
+          if (i != FoundIndex)
+            Ops.push_back(Add->getOperand(i));
+        const SCEV *Accum = getAddExpr(Ops);
+
+        // This is not a valid addrec if the step amount is varying each
+        // loop iteration, but is not itself an addrec in this loop.
+        if (isLoopInvariant(Accum, L) ||
+            (isa<SCEVAddRecExpr>(Accum) &&
+             cast<SCEVAddRecExpr>(Accum)->getLoop() == L)) {
+          SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap;
+
+          // If the increment doesn't overflow, then neither the addrec nor
+          // the post-increment will overflow.
+          if (const AddOperator *OBO = dyn_cast<AddOperator>(BEValueV)) {
+            if (OBO->getOperand(0) == PN) {
+              if (OBO->hasNoUnsignedWrap())
+                Flags = setFlags(Flags, SCEV::FlagNUW);
+              if (OBO->hasNoSignedWrap())
+                Flags = setFlags(Flags, SCEV::FlagNSW);
             }
-          }
-        } else if (const SCEVAddRecExpr *AddRec =
-                     dyn_cast<SCEVAddRecExpr>(BEValue)) {
-          // Otherwise, this could be a loop like this:
-          //     i = 0;  for (j = 1; ..; ++j) { ....  i = j; }
-          // In this case, j = {1,+,1}  and BEValue is j.
-          // Because the other in-value of i (0) fits the evolution of BEValue
-          // i really is an addrec evolution.
-          if (AddRec->getLoop() == L && AddRec->isAffine()) {
-            const SCEV *StartVal = getSCEV(StartValueV);
-
-            // If StartVal = j.start - j.stride, we can use StartVal as the
-            // initial step of the addrec evolution.
-            if (StartVal == getMinusSCEV(AddRec->getOperand(0),
-                                         AddRec->getOperand(1))) {
-              // FIXME: For constant StartVal, we should be able to infer
-              // no-wrap flags.
-              const SCEV *PHISCEV =
-                getAddRecExpr(StartVal, AddRec->getOperand(1), L,
-                              SCEV::FlagAnyWrap);
-
-              // Okay, for the entire analysis of this edge we assumed the PHI
-              // to be symbolic.  We now need to go back and purge all of the
-              // entries for the scalars that use the symbolic expression.
-              ForgetSymbolicName(PN, SymbolicName);
-              ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV;
-              return PHISCEV;
+          } else if (GEPOperator *GEP = dyn_cast<GEPOperator>(BEValueV)) {
+            // If the increment is an inbounds GEP, then we know the address
+            // space cannot be wrapped around. We cannot make any guarantee
+            // about signed or unsigned overflow because pointers are
+            // unsigned but we may have a negative index from the base
+            // pointer. We can guarantee that no unsigned wrap occurs if the
+            // indices form a positive value.
+            if (GEP->isInBounds() && GEP->getOperand(0) == PN) {
+              Flags = setFlags(Flags, SCEV::FlagNW);
+
+              const SCEV *Ptr = getSCEV(GEP->getPointerOperand());
+              if (isKnownPositive(getMinusSCEV(getSCEV(GEP), Ptr)))
+                Flags = setFlags(Flags, SCEV::FlagNUW);
             }
+
+            // We cannot transfer nuw and nsw flags from subtraction
+            // operations -- sub nuw X, Y is not the same as add nuw X, -Y
+            // for instance.
           }
+
+          const SCEV *StartVal = getSCEV(StartValueV);
+          const SCEV *PHISCEV = getAddRecExpr(StartVal, Accum, L, Flags);
+
+          // Since the no-wrap flags are on the increment, they apply to the
+          // post-incremented value as well.
+          if (isLoopInvariant(Accum, L))
+            (void)getAddRecExpr(getAddExpr(StartVal, Accum), Accum, L, Flags);
+
+          // Okay, for the entire analysis of this edge we assumed the PHI
+          // to be symbolic.  We now need to go back and purge all of the
+          // entries for the scalars that use the symbolic expression.
+          ForgetSymbolicName(PN, SymbolicName);
+          ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV;
+          return PHISCEV;
+        }
+      }
+    } else if (const SCEVAddRecExpr *AddRec =
+                   dyn_cast<SCEVAddRecExpr>(BEValue)) {
+      // Otherwise, this could be a loop like this:
+      //     i = 0;  for (j = 1; ..; ++j) { ....  i = j; }
+      // In this case, j = {1,+,1}  and BEValue is j.
+      // Because the other in-value of i (0) fits the evolution of BEValue
+      // i really is an addrec evolution.
+      if (AddRec->getLoop() == L && AddRec->isAffine()) {
+        const SCEV *StartVal = getSCEV(StartValueV);
+
+        // If StartVal = j.start - j.stride, we can use StartVal as the
+        // initial step of the addrec evolution.
+        if (StartVal ==
+            getMinusSCEV(AddRec->getOperand(0), AddRec->getOperand(1))) {
+          // FIXME: For constant StartVal, we should be able to infer
+          // no-wrap flags.
+          const SCEV *PHISCEV = getAddRecExpr(StartVal, AddRec->getOperand(1),
+                                              L, SCEV::FlagAnyWrap);
+
+          // Okay, for the entire analysis of this edge we assumed the PHI
+          // to be symbolic.  We now need to go back and purge all of the
+          // entries for the scalars that use the symbolic expression.
+          ForgetSymbolicName(PN, SymbolicName);
+          ValueExprMap[SCEVCallbackVH(PN, this)] = PHISCEV;
+          return PHISCEV;
         }
       }
     }
+  }
+
+  return nullptr;
+}
+
+const SCEV *ScalarEvolution::createNodeFromSelectLikePHI(PHINode *PN) {
+  const Loop *L = LI.getLoopFor(PN->getParent());
+
+  // Try to match a control flow sequence that branches out at BI and merges
+  // back at Merge into a "C ? LHS : RHS" select pattern.  Return true on a
+  // successful match.
+  auto BrPHIToSelect = [&](BranchInst *BI, PHINode *Merge, Value *&C,
+                           Value *&LHS, Value *&RHS) {
+    C = BI->getCondition();
+
+    BasicBlockEdge LeftEdge(BI->getParent(), BI->getSuccessor(0));
+    BasicBlockEdge RightEdge(BI->getParent(), BI->getSuccessor(1));
+
+    if (!LeftEdge.isSingleEdge())
+      return false;
+
+    assert(RightEdge.isSingleEdge() && "Follows from LeftEdge.isSingleEdge()");
+
+    Use &LeftUse = Merge->getOperandUse(0);
+    Use &RightUse = Merge->getOperandUse(1);
+
+    if (DT.dominates(LeftEdge, LeftUse) && DT.dominates(RightEdge, RightUse)) {
+      LHS = LeftUse;
+      RHS = RightUse;
+      return true;
+    }
+
+    if (DT.dominates(LeftEdge, RightUse) && DT.dominates(RightEdge, LeftUse)) {
+      LHS = RightUse;
+      RHS = LeftUse;
+      return true;
+    }
+
+    return false;
+  };
+
+  // Checks if the SCEV S is available at BB.  S is considered available at BB
+  // if S can be materialized at BB without introducing a fault.
+  auto IsAvailableOnEntry = [&](const SCEV *S, BasicBlock *BB) {
+    struct CheckAvailable {
+      bool TraversalDone = false;
+      bool Available = true;
+
+      const Loop *L = nullptr;  // The loop BB is in (can be nullptr)
+      BasicBlock *BB = nullptr;
+      DominatorTree &DT;
+
+      CheckAvailable(const Loop *L, BasicBlock *BB, DominatorTree &DT)
+          : L(L), BB(BB), DT(DT) {}
+
+      bool setUnavailable() {
+        TraversalDone = true;
+        Available = false;
+        return false;
+      }
+
+      bool follow(const SCEV *S) {
+        switch (S->getSCEVType()) {
+        case scConstant: case scTruncate: case scZeroExtend: case scSignExtend:
+        case scAddExpr: case scMulExpr: case scUMaxExpr: case scSMaxExpr:
+          // These expressions are available if their operand(s) is/are.
+          return true;
+
+        case scAddRecExpr: {
+          // We allow add recurrences that are on the loop BB is in, or some
+          // outer loop.  This guarantees availability because the value of the
+          // add recurrence at BB is simply the "current" value of the induction
+          // variable.  We can relax this in the future; for instance an add
+          // recurrence on a sibling dominating loop is also available at BB.
+          const auto *ARLoop = cast<SCEVAddRecExpr>(S)->getLoop();
+          if (L && (ARLoop == L || ARLoop->contains(L)))
+            return true;
+
+          return setUnavailable();
+        }
+
+        case scUnknown: {
+          // For SCEVUnknown, we check for simple dominance.
+          const auto *SU = cast<SCEVUnknown>(S);
+          Value *V = SU->getValue();
+
+          if (isa<Argument>(V))
+            return false;
+
+          if (isa<Instruction>(V) && DT.dominates(cast<Instruction>(V), BB))
+            return false;
+
+          return setUnavailable();
+        }
+
+        case scUDivExpr:
+        case scCouldNotCompute:
+          // We do not try to smart about these at all.
+          return setUnavailable();
+        }
+        llvm_unreachable("switch should be fully covered!");
+      }
+
+      bool isDone() { return TraversalDone; }
+    };
+
+    CheckAvailable CA(L, BB, DT);
+    SCEVTraversal<CheckAvailable> ST(CA);
+
+    ST.visitAll(S);
+    return CA.Available;
+  };
+
+  if (PN->getNumIncomingValues() == 2) {
+    // Try to match
+    //
+    //  br %cond, label %left, label %right
+    // left:
+    //  br label %merge
+    // right:
+    //  br label %merge
+    // merge:
+    //  V = phi [ %x, %left ], [ %y, %right ]
+    //
+    // as "select %cond, %x, %y"
+
+    BasicBlock *IDom = DT[PN->getParent()]->getIDom()->getBlock();
+    assert(IDom && "At least the entry block should dominate PN");
+
+    auto *BI = dyn_cast<BranchInst>(IDom->getTerminator());
+    Value *Cond = nullptr, *LHS = nullptr, *RHS = nullptr;
+
+    if (BI && BI->isConditional() && BrPHIToSelect(BI, PN, Cond, LHS, RHS) &&
+        IsAvailableOnEntry(getSCEV(LHS), PN->getParent()) &&
+        IsAvailableOnEntry(getSCEV(RHS), PN->getParent()))
+      return createNodeForSelectOrPHI(PN, Cond, LHS, RHS);
+  }
+
+  return nullptr;
+}
+
+const SCEV *ScalarEvolution::createNodeForPHI(PHINode *PN) {
+  if (const SCEV *S = createAddRecFromPHI(PN))
+    return S;
+
+  if (const SCEV *S = createNodeFromSelectLikePHI(PN))
+    return S;
 
   // If the PHI has a single incoming value, follow that value, unless the
   // PHI's incoming blocks are in a different loop, in which case doing so
@@ -3756,9 +3898,10 @@ const SCEV *ScalarEvolution::createNodeF
   return getUnknown(PN);
 }
 
-const SCEV *ScalarEvolution::createNodeForSelect(Instruction *I, Value *Cond,
-                                                 Value *TrueVal,
-                                                 Value *FalseVal) {
+const SCEV *ScalarEvolution::createNodeForSelectOrPHI(Instruction *I,
+                                                      Value *Cond,
+                                                      Value *TrueVal,
+                                                      Value *FalseVal) {
   // Try to match some simple smax or umax patterns.
   auto *ICI = dyn_cast<ICmpInst>(Cond);
   if (!ICI)
@@ -4568,8 +4711,8 @@ const SCEV *ScalarEvolution::createSCEV(
     // constant expressions cannot have instructions as operands, we'd have
     // returned getUnknown for a select constant expressions anyway.
     if (isa<Instruction>(U))
-      return createNodeForSelect(cast<Instruction>(U), U->getOperand(0),
-                                 U->getOperand(1), U->getOperand(2));
+      return createNodeForSelectOrPHI(cast<Instruction>(U), U->getOperand(0),
+                                      U->getOperand(1), U->getOperand(2));
 
   default: // We cannot analyze this expression.
     break;

Added: llvm/trunk/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll?rev=249211&view=auto
==============================================================================
--- llvm/trunk/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll (added)
+++ llvm/trunk/test/Analysis/ScalarEvolution/smax-br-phi-idioms.ll Fri Oct  2 18:09:44 2015
@@ -0,0 +1,104 @@
+; RUN: opt -analyze -scalar-evolution < %s | FileCheck %s
+
+define i32 @f0(i32 %x, i32 %y) {
+; CHECK-LABEL: Classifying expressions for: @f0
+ entry:
+  %c = icmp sgt i32 %y, 0
+  br i1 %c, label %add, label %merge
+
+ add:
+  %sum = add i32 %x, %y
+  br label %merge
+
+ merge:
+  %v = phi i32 [ %sum, %add ], [ %x, %entry ]
+; CHECK:  %v = phi i32 [ %sum, %add ], [ %x, %entry ]
+; CHECK-NEXT:  -->  ((0 smax %y) + %x) U: full-set S: full-set
+  ret i32 %v
+}
+
+define i32 @f1(i32 %x, i32 %y) {
+; CHECK-LABEL: Classifying expressions for: @f1
+ entry:
+  %c = icmp sge i32 %y, 0
+  br i1 %c, label %add, label %merge
+
+ add:
+  %sum = add i32 %x, %y
+  br label %merge
+
+ merge:
+  %v = phi i32 [ %sum, %add ], [ %x, %entry ]
+; CHECK:  %v = phi i32 [ %sum, %add ], [ %x, %entry ]
+; CHECK-NEXT:  -->  ((0 smax %y) + %x) U: full-set S: full-set
+  ret i32 %v
+}
+
+define i32 @f2(i32 %x, i32 %y, i32* %ptr) {
+; CHECK-LABEL: Classifying expressions for: @f2
+ entry:
+  %c = icmp sge i32 %y, 0
+  br i1 %c, label %add, label %merge
+
+ add:
+  %lv = load i32, i32* %ptr
+  br label %merge
+
+ merge:
+  %v = phi i32 [ %lv, %add ], [ %x, %entry ]
+; CHECK:  %v = phi i32 [ %lv, %add ], [ %x, %entry ]
+; CHECK-NEXT:  -->  %v U: full-set S: full-set
+  ret i32 %v
+}
+
+define i32 @f3(i32 %x, i32 %init, i32 %lim) {
+; CHECK-LABEL: Classifying expressions for: @f3
+ entry:
+  br label %loop
+
+loop:
+  %iv = phi i32 [ %init, %entry ], [ %iv.inc, %merge ]
+  %iv.inc = add i32 %iv, 1
+  %c = icmp sge i32 %iv, 0
+  br i1 %c, label %add, label %merge
+
+ add:
+  %sum = add i32 %x, %iv
+  br label %merge
+
+ merge:
+  %v = phi i32 [ %sum, %add ], [ %x, %loop ]
+; CHECK:  %v = phi i32 [ %sum, %add ], [ %x, %loop ]
+; CHECK-NEXT:  -->  ((0 smax {%init,+,1}<%loop>) + %x) U: full-set S: full-set
+  %be.cond = icmp eq i32 %iv.inc, %lim
+  br i1 %be.cond, label %loop, label %leave
+
+ leave:
+  ret i32 0
+}
+
+define i32 @f4(i32 %x, i32 %init, i32 %lim) {
+; CHECK-LABEL: Classifying expressions for: @f4
+ entry:
+  %c = icmp sge i32 %init, 0
+  br i1 %c, label %add, label %merge
+
+ add:
+  br label %loop
+
+ loop:
+  %iv = phi i32 [ %init, %add ], [ %iv.inc, %loop ]
+  %iv.inc = add i32 %iv, 1
+  %be.cond = icmp eq i32 %iv.inc, %lim
+  br i1 %be.cond, label %loop, label %add.cont
+
+ add.cont:
+  %sum = add i32 %x, %iv
+  br label %merge
+
+ merge:
+  %v = phi i32 [ %sum, %add.cont ], [ %x, %entry ]
+; CHECK:  %v = phi i32 [ %sum, %add.cont ], [ %x, %entry ]
+; CHECK-NEXT:  -->  %v U: full-set S: full-set
+  ret i32 %v
+}




More information about the llvm-commits mailing list