[llvm-branch-commits] [llvm] ca4ed1e - [PredicateInfo] Generalize processing of conditions

Nikita Popov via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jan 20 11:45:33 PST 2021


Author: Nikita Popov
Date: 2021-01-20T20:40:41+01:00
New Revision: ca4ed1e7aeebe21dc3952f84b408805ab17ad63f

URL: https://github.com/llvm/llvm-project/commit/ca4ed1e7aeebe21dc3952f84b408805ab17ad63f
DIFF: https://github.com/llvm/llvm-project/commit/ca4ed1e7aeebe21dc3952f84b408805ab17ad63f.diff

LOG: [PredicateInfo] Generalize processing of conditions

Branch/assume conditions in PredicateInfo are currently handled in
a rather ad-hoc manner, with some arbitrary limitations. For example,
an `and` of two `icmp`s will be handled, but an `and` of an `icmp`
and some other condition will not. That also includes the case where
more than two conditions and and'ed together.

This patch makes the handling more general by looking through and/ors
up to a limit and considering all kinds of conditions (though operands
will only be taken for cmps of course).

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

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/PredicateInfo.cpp
    llvm/test/Transforms/NewGVN/assume-equal.ll
    llvm/test/Transforms/SCCP/conditions-ranges.ll
    llvm/test/Transforms/Util/PredicateInfo/condprop.ll
    llvm/test/Transforms/Util/PredicateInfo/testandor.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/PredicateInfo.cpp b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
index d9bd77e999da..9b6f7d32054f 100644
--- a/llvm/lib/Transforms/Utils/PredicateInfo.cpp
+++ b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
@@ -53,6 +53,10 @@ static cl::opt<bool> VerifyPredicateInfo(
 DEBUG_COUNTER(RenameCounter, "predicateinfo-rename",
               "Controls which variables are renamed with predicateinfo");
 
+// Maximum number of conditions considered for renaming for each branch/assume.
+// This limits renaming of deep and/or chains.
+static const unsigned MaxCondsPerBranch = 8;
+
 namespace {
 // Given a predicate info that is a type of branching terminator, get the
 // branching block.
@@ -367,6 +371,13 @@ void PredicateInfoBuilder::convertUsesToDFSOrdered(
   }
 }
 
+bool shouldRename(Value *V) {
+  // Only want real values, not constants.  Additionally, operands with one use
+  // are only being used in the comparison, which means they will not be useful
+  // for us to consider for predicateinfo.
+  return (isa<Instruction>(V) || isa<Argument>(V)) && !V->hasOneUse();
+}
+
 // Collect relevant operations from Comparison that we may want to insert copies
 // for.
 void collectCmpOps(CmpInst *Comparison, SmallVectorImpl<Value *> &CmpOperands) {
@@ -374,15 +385,9 @@ void collectCmpOps(CmpInst *Comparison, SmallVectorImpl<Value *> &CmpOperands) {
   auto *Op1 = Comparison->getOperand(1);
   if (Op0 == Op1)
     return;
-  CmpOperands.push_back(Comparison);
-  // Only want real values, not constants.  Additionally, operands with one use
-  // are only being used in the comparison, which means they will not be useful
-  // for us to consider for predicateinfo.
-  //
-  if ((isa<Instruction>(Op0) || isa<Argument>(Op0)) && !Op0->hasOneUse())
-    CmpOperands.push_back(Op0);
-  if ((isa<Instruction>(Op1) || isa<Argument>(Op1)) && !Op1->hasOneUse())
-    CmpOperands.push_back(Op1);
+
+  CmpOperands.push_back(Op0);
+  CmpOperands.push_back(Op1);
 }
 
 // Add Op, PB to the list of value infos for Op, and mark Op to be renamed.
@@ -400,38 +405,32 @@ void PredicateInfoBuilder::addInfoFor(SmallVectorImpl<Value *> &OpsToRename,
 void PredicateInfoBuilder::processAssume(
     IntrinsicInst *II, BasicBlock *AssumeBB,
     SmallVectorImpl<Value *> &OpsToRename) {
-  // See if we have a comparison we support
-  SmallVector<Value *, 8> CmpOperands;
-  SmallVector<Value *, 2> ConditionsToProcess;
-  CmpInst::Predicate Pred;
-  Value *Operand = II->getOperand(0);
-  if (m_c_And(m_Cmp(Pred, m_Value(), m_Value()),
-              m_Cmp(Pred, m_Value(), m_Value()))
-          .match(II->getOperand(0))) {
-    ConditionsToProcess.push_back(cast<BinaryOperator>(Operand)->getOperand(0));
-    ConditionsToProcess.push_back(cast<BinaryOperator>(Operand)->getOperand(1));
-    ConditionsToProcess.push_back(Operand);
-  } else if (isa<CmpInst>(Operand)) {
-
-    ConditionsToProcess.push_back(Operand);
-  }
-  for (auto Cond : ConditionsToProcess) {
-    if (auto *Cmp = dyn_cast<CmpInst>(Cond)) {
-      collectCmpOps(Cmp, CmpOperands);
-      // Now add our copy infos for our operands
-      for (auto *Op : CmpOperands) {
-        auto *PA = new PredicateAssume(Op, II, Cmp);
-        addInfoFor(OpsToRename, Op, PA);
+  SmallVector<Value *, 4> Worklist;
+  SmallPtrSet<Value *, 4> Visited;
+  Worklist.push_back(II->getOperand(0));
+  while (!Worklist.empty()) {
+    Value *Cond = Worklist.pop_back_val();
+    if (!Visited.insert(Cond).second)
+      continue;
+    if (Visited.size() > MaxCondsPerBranch)
+      break;
+
+    Value *Op0, *Op1;
+    if (match(Cond, m_And(m_Value(Op0), m_Value(Op1)))) {
+      Worklist.push_back(Op1);
+      Worklist.push_back(Op0);
+    }
+
+    SmallVector<Value *, 4> Values;
+    Values.push_back(Cond);
+    if (auto *Cmp = dyn_cast<CmpInst>(Cond))
+      collectCmpOps(Cmp, Values);
+
+    for (Value *V : Values) {
+      if (shouldRename(V)) {
+        auto *PA = new PredicateAssume(V, II, Cond);
+        addInfoFor(OpsToRename, V, PA);
       }
-      CmpOperands.clear();
-    } else if (auto *BinOp = dyn_cast<BinaryOperator>(Cond)) {
-      // Otherwise, it should be an AND.
-      assert(BinOp->getOpcode() == Instruction::And &&
-             "Should have been an AND");
-      auto *PA = new PredicateAssume(BinOp, II, BinOp);
-      addInfoFor(OpsToRename, BinOp, PA);
-    } else {
-      llvm_unreachable("Unknown type of condition");
     }
   }
 }
@@ -443,68 +442,46 @@ void PredicateInfoBuilder::processBranch(
     SmallVectorImpl<Value *> &OpsToRename) {
   BasicBlock *FirstBB = BI->getSuccessor(0);
   BasicBlock *SecondBB = BI->getSuccessor(1);
-  SmallVector<BasicBlock *, 2> SuccsToProcess;
-  SuccsToProcess.push_back(FirstBB);
-  SuccsToProcess.push_back(SecondBB);
-  SmallVector<Value *, 2> ConditionsToProcess;
-
-  auto InsertHelper = [&](Value *Op, bool isAnd, bool isOr, Value *Cond) {
-    for (auto *Succ : SuccsToProcess) {
-      // Don't try to insert on a self-edge. This is mainly because we will
-      // eliminate during renaming anyway.
-      if (Succ == BranchBB)
-        continue;
-      bool TakenEdge = (Succ == FirstBB);
-      // For and, only insert on the true edge
-      // For or, only insert on the false edge
-      if ((isAnd && !TakenEdge) || (isOr && TakenEdge))
+
+  for (BasicBlock *Succ : {FirstBB, SecondBB}) {
+    bool TakenEdge = Succ == FirstBB;
+    // Don't try to insert on a self-edge. This is mainly because we will
+    // eliminate during renaming anyway.
+    if (Succ == BranchBB)
+      continue;
+
+    SmallVector<Value *, 4> Worklist;
+    SmallPtrSet<Value *, 4> Visited;
+    Worklist.push_back(BI->getCondition());
+    while (!Worklist.empty()) {
+      Value *Cond = Worklist.pop_back_val();
+      if (!Visited.insert(Cond).second)
         continue;
-      PredicateBase *PB =
-          new PredicateBranch(Op, BranchBB, Succ, Cond, TakenEdge);
-      addInfoFor(OpsToRename, Op, PB);
-      if (!Succ->getSinglePredecessor())
-        EdgeUsesOnly.insert({BranchBB, Succ});
-    }
-  };
+      if (Visited.size() > MaxCondsPerBranch)
+        break;
+
+      Value *Op0, *Op1;
+      if (TakenEdge ? match(Cond, m_And(m_Value(Op0), m_Value(Op1)))
+                    : match(Cond, m_Or(m_Value(Op0), m_Value(Op1)))) {
+        Worklist.push_back(Op1);
+        Worklist.push_back(Op0);
+      }
 
-  // Match combinations of conditions.
-  CmpInst::Predicate Pred;
-  bool isAnd = false;
-  bool isOr = false;
-  SmallVector<Value *, 8> CmpOperands;
-  if (match(BI->getCondition(), m_And(m_Cmp(Pred, m_Value(), m_Value()),
-                                      m_Cmp(Pred, m_Value(), m_Value()))) ||
-      match(BI->getCondition(), m_Or(m_Cmp(Pred, m_Value(), m_Value()),
-                                     m_Cmp(Pred, m_Value(), m_Value())))) {
-    auto *BinOp = cast<BinaryOperator>(BI->getCondition());
-    if (BinOp->getOpcode() == Instruction::And)
-      isAnd = true;
-    else if (BinOp->getOpcode() == Instruction::Or)
-      isOr = true;
-    ConditionsToProcess.push_back(BinOp->getOperand(0));
-    ConditionsToProcess.push_back(BinOp->getOperand(1));
-    ConditionsToProcess.push_back(BI->getCondition());
-  } else if (isa<CmpInst>(BI->getCondition())) {
-    ConditionsToProcess.push_back(BI->getCondition());
-  }
-  for (auto Cond : ConditionsToProcess) {
-    if (auto *Cmp = dyn_cast<CmpInst>(Cond)) {
-      collectCmpOps(Cmp, CmpOperands);
-      // Now add our copy infos for our operands
-      for (auto *Op : CmpOperands)
-        InsertHelper(Op, isAnd, isOr, Cmp);
-    } else if (auto *BinOp = dyn_cast<BinaryOperator>(Cond)) {
-      // This must be an AND or an OR.
-      assert((BinOp->getOpcode() == Instruction::And ||
-              BinOp->getOpcode() == Instruction::Or) &&
-             "Should have been an AND or an OR");
-      // The actual value of the binop is not subject to the same restrictions
-      // as the comparison. It's either true or false on the true/false branch.
-      InsertHelper(BinOp, false, false, BinOp);
-    } else {
-      llvm_unreachable("Unknown type of condition");
+      SmallVector<Value *, 4> Values;
+      Values.push_back(Cond);
+      if (auto *Cmp = dyn_cast<CmpInst>(Cond))
+        collectCmpOps(Cmp, Values);
+
+      for (Value *V : Values) {
+        if (shouldRename(V)) {
+          PredicateBase *PB =
+              new PredicateBranch(V, BranchBB, Succ, Cond, TakenEdge);
+          addInfoFor(OpsToRename, V, PB);
+          if (!Succ->getSinglePredecessor())
+            EdgeUsesOnly.insert({BranchBB, Succ});
+        }
+      }
     }
-    CmpOperands.clear();
   }
 }
 // Process a block terminating switch, and place relevant operations to be

diff  --git a/llvm/test/Transforms/NewGVN/assume-equal.ll b/llvm/test/Transforms/NewGVN/assume-equal.ll
index d67105fbf1a2..f0e4f25d17b7 100644
--- a/llvm/test/Transforms/NewGVN/assume-equal.ll
+++ b/llvm/test/Transforms/NewGVN/assume-equal.ll
@@ -106,7 +106,7 @@ define i32 @_Z1il(i32 %val, i1 %k) {
 ; CHECK-NEXT:    br label [[NEXT:%.*]]
 ; CHECK:       next:
 ; CHECK-NEXT:    tail call void @llvm.assume(i1 [[K:%.*]])
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[K]])
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[VAL:%.*]], 50
 ; CHECK-NEXT:    br i1 [[CMP]], label [[NEXT]], label [[MEH:%.*]]
 ; CHECK:       meh:
@@ -132,7 +132,7 @@ define i1 @_z1im(i32 %val, i1 %k, i1 %j) {
 ; CHECK-NEXT:    br i1 [[J:%.*]], label [[NEXT:%.*]], label [[MEH:%.*]]
 ; CHECK:       next:
 ; CHECK-NEXT:    tail call void @llvm.assume(i1 [[K:%.*]])
-; CHECK-NEXT:    tail call void @llvm.assume(i1 [[K]])
+; CHECK-NEXT:    tail call void @llvm.assume(i1 true)
 ; CHECK-NEXT:    br label [[MEH]]
 ; CHECK:       meh:
 ; CHECK-NEXT:    ret i1 [[K]]

diff  --git a/llvm/test/Transforms/SCCP/conditions-ranges.ll b/llvm/test/Transforms/SCCP/conditions-ranges.ll
index 65c3440a207c..2317242e5e6c 100644
--- a/llvm/test/Transforms/SCCP/conditions-ranges.ll
+++ b/llvm/test/Transforms/SCCP/conditions-ranges.ll
@@ -966,8 +966,6 @@ true:
   ret void
 }
 
-; TODO: Currently only the information of the AND used as branch condition is
-; used.
 define void @f18_conditions_chained_and(i32 %a, i32 %b) {
 ; CHECK-LABEL: @f18_conditions_chained_and(
 ; CHECK-NEXT:  entry:
@@ -978,18 +976,12 @@ define void @f18_conditions_chained_and(i32 %a, i32 %b) {
 ; CHECK-NEXT:    [[BC_2:%.*]] = and i1 [[BC]], [[B_LT]]
 ; CHECK-NEXT:    br i1 [[BC_2]], label [[TRUE:%.*]], label [[FALSE:%.*]]
 ; CHECK:       true:
-; CHECK-NEXT:    [[F_1:%.*]] = icmp eq i32 [[A]], 0
-; CHECK-NEXT:    call void @use(i1 [[F_1]])
-; CHECK-NEXT:    [[F_2:%.*]] = icmp eq i32 [[A]], 20
-; CHECK-NEXT:    call void @use(i1 [[F_2]])
-; CHECK-NEXT:    [[F_3:%.*]] = icmp ugt i32 [[A]], 100
-; CHECK-NEXT:    call void @use(i1 [[F_3]])
-; CHECK-NEXT:    [[F_4:%.*]] = icmp ugt i32 [[B]], 100
-; CHECK-NEXT:    call void @use(i1 [[F_4]])
-; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i32 [[A]], 100
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp ne i32 [[A]], 20
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp eq i32 [[A]], 21
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[A]], 21

diff  --git a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
index 4f5f07878cd2..689326b6ca97 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -print-predicateinfo < %s 2>&1 | FileCheck %s
+; RUN: opt -print-predicateinfo -disable-output < %s 2>&1 | FileCheck %s
 
 @a = external global i32		; <i32*> [#uses=7]
 
@@ -98,11 +98,11 @@ define void @test3(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
 ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
+; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
 ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
 ; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
-; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH_ZERO:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both_zero:
 ; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])
@@ -138,8 +138,8 @@ define void @test4(i1 %b, i32 %x) {
 ; CHECK-NEXT:    i32 2, label [[CASE0]]
 ; CHECK-NEXT:    i32 3, label [[CASE3]]
 ; CHECK-NEXT:    i32 4, label [[DEFAULT:%.*]]
-; CHECK-NEXT:    ] Edge: [label [[SW]],label %case1]
-; CHECK-NEXT:    [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X:%.*]])
+; CHECK-NEXT:    ] Edge: [label [[SW]],label %case1], RenamedOp: [[X:%.*]] }
+; CHECK-NEXT:    [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT]] [
 ; CHECK-NEXT:    i32 0, label [[CASE0]]
 ; CHECK-NEXT:    i32 1, label [[CASE1]]

diff  --git a/llvm/test/Transforms/Util/PredicateInfo/testandor.ll b/llvm/test/Transforms/Util/PredicateInfo/testandor.ll
index a3d8e78b5283..8ce56ac02cbb 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/testandor.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/testandor.ll
@@ -10,11 +10,11 @@ define void @testor(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
 ; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
+; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
 ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
 ; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
-; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK-NEXT:    br i1 [[Z]], label [[ONEOF:%.*]], label [[NEITHER:%.*]]
 ; CHECK:       oneof:
 ; CHECK-NEXT:    call void @foo(i1 [[XZ]])
@@ -54,11 +54,11 @@ define void @testand(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[XZ:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
 ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
+; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK:         [[XZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
 ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK:         [[YZ_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
 ; CHECK:         [[Y_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
-; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both:
 ; CHECK-NEXT:    call void @foo(i1 [[XZ_0]])
@@ -98,11 +98,11 @@ define void @testandsame(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[XGT:%.*]] = icmp sgt i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[XLT:%.*]] = icmp slt i32 [[X]], 100
 ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XGT]], [[XLT]]
+; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK:         [[XGT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XGT]])
 ; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK:         [[X_0_1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X_0]])
 ; CHECK:         [[XLT_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XLT]])
-; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both:
 ; CHECK-NEXT:    call void @foo(i1 [[XGT_0]])
@@ -137,25 +137,25 @@ define void @testandassume(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
 ; CHECK-NEXT:    [[Z:%.*]] = and i1 [[XZ]], [[YZ]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]])
-; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
-; CHECK:         [[TMP2:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
-; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
-; CHECK:         [[TMP4:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
-; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK:         [[TMP1:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[Y]])
+; CHECK:         [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[YZ]])
+; CHECK:         [[TMP3:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
+; CHECK:         [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[XZ]])
+; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
 ; CHECK:         [[DOT0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP5]])
-; CHECK:         [[DOT01:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP4]])
-; CHECK:         [[DOT02:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP3]])
-; CHECK:         [[DOT03:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP2]])
-; CHECK:         [[DOT04:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP1]])
-; CHECK-NEXT:    br i1 [[TMP1]], label [[BOTH:%.*]], label [[NOPE:%.*]]
+; CHECK:         [[DOT01:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP4]])
+; CHECK:         [[DOT02:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP3]])
+; CHECK:         [[DOT03:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP2]])
+; CHECK:         [[DOT04:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[TMP1]])
+; CHECK-NEXT:    br i1 [[TMP5]], label [[BOTH:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both:
-; CHECK-NEXT:    call void @foo(i1 [[DOT0]])
-; CHECK-NEXT:    call void @foo(i1 [[DOT02]])
-; CHECK-NEXT:    call void @bar(i32 [[DOT01]])
-; CHECK-NEXT:    call void @bar(i32 [[DOT03]])
+; CHECK-NEXT:    call void @foo(i1 [[DOT01]])
+; CHECK-NEXT:    call void @foo(i1 [[DOT03]])
+; CHECK-NEXT:    call void @bar(i32 [[DOT02]])
+; CHECK-NEXT:    call void @bar(i32 [[DOT04]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       nope:
-; CHECK-NEXT:    call void @foo(i1 [[DOT04]])
+; CHECK-NEXT:    call void @foo(i1 [[DOT0]])
 ; CHECK-NEXT:    ret void
 ;
   %xz = icmp eq i32 %x, 0
@@ -182,8 +182,9 @@ define void @testorassume(i32 %x, i32 %y) {
 ; CHECK-NEXT:    [[YZ:%.*]] = icmp eq i32 [[Y:%.*]], 0
 ; CHECK-NEXT:    [[Z:%.*]] = or i1 [[XZ]], [[YZ]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[Z]])
-; CHECK:         [[Z_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
-; CHECK-NEXT:    br i1 [[Z]], label [[BOTH:%.*]], label [[NOPE:%.*]]
+; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[Z]])
+; CHECK:         [[DOT0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[TMP1]])
+; CHECK-NEXT:    br i1 [[TMP1]], label [[BOTH:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both:
 ; CHECK-NEXT:    call void @foo(i1 [[XZ]])
 ; CHECK-NEXT:    call void @foo(i1 [[YZ]])
@@ -191,7 +192,7 @@ define void @testorassume(i32 %x, i32 %y) {
 ; CHECK-NEXT:    call void @bar(i32 [[Y]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       nope:
-; CHECK-NEXT:    call void @foo(i1 [[Z_0]])
+; CHECK-NEXT:    call void @foo(i1 [[DOT0]])
 ; CHECK-NEXT:    ret void
 ;
   %xz = icmp eq i32 %x, 0
@@ -214,18 +215,23 @@ define void @test_and_one_unknown_cond(i32 %x, i1 %c1) {
 ; CHECK-LABEL: @test_and_one_unknown_cond(
 ; CHECK-NEXT:    [[C2:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[A:%.*]] = and i1 [[C1:%.*]], [[C2]]
+; CHECK:         [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[A_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[C1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C1]])
+; CHECK:         [[C2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C2]])
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK-NEXT:    br i1 [[A]], label [[BOTH:%.*]], label [[NOPE:%.*]]
 ; CHECK:       both:
-; CHECK-NEXT:    call void @bar(i32 [[X]])
-; CHECK-NEXT:    call void @foo(i1 [[C1]])
-; CHECK-NEXT:    call void @foo(i1 [[C2]])
-; CHECK-NEXT:    call void @foo(i1 [[A]])
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C1_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C2_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       nope:
 ; CHECK-NEXT:    call void @bar(i32 [[X]])
 ; CHECK-NEXT:    call void @foo(i1 [[C1]])
 ; CHECK-NEXT:    call void @foo(i1 [[C2]])
-; CHECK-NEXT:    call void @foo(i1 [[A]])
+; CHECK-NEXT:    call void @foo(i1 [[A_1]])
 ; CHECK-NEXT:    ret void
 ;
   %c2 = icmp eq i32 %x, 0
@@ -251,18 +257,23 @@ define void @test_or_one_unknown_cond(i32 %x, i1 %c1) {
 ; CHECK-LABEL: @test_or_one_unknown_cond(
 ; CHECK-NEXT:    [[C2:%.*]] = icmp eq i32 [[X:%.*]], 0
 ; CHECK-NEXT:    [[A:%.*]] = or i1 [[C1:%.*]], [[C2]]
+; CHECK:         [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[A_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[C1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C1]])
+; CHECK:         [[C2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C2]])
+; CHECK:         [[X_0:%.*]] = call i32 @llvm.ssa.copy.{{.+}}(i32 [[X]])
 ; CHECK-NEXT:    br i1 [[A]], label [[NOPE:%.*]], label [[BOTH_INVERTED:%.*]]
 ; CHECK:       both_inverted:
-; CHECK-NEXT:    call void @bar(i32 [[X]])
-; CHECK-NEXT:    call void @foo(i1 [[C1]])
-; CHECK-NEXT:    call void @foo(i1 [[C2]])
-; CHECK-NEXT:    call void @foo(i1 [[A]])
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C1_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C2_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A_1]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       nope:
 ; CHECK-NEXT:    call void @bar(i32 [[X]])
 ; CHECK-NEXT:    call void @foo(i1 [[C1]])
 ; CHECK-NEXT:    call void @foo(i1 [[C2]])
-; CHECK-NEXT:    call void @foo(i1 [[A]])
+; CHECK-NEXT:    call void @foo(i1 [[A_0]])
 ; CHECK-NEXT:    ret void
 ;
   %c2 = icmp eq i32 %x, 0
@@ -288,20 +299,26 @@ define void @test_and_chain(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @test_and_chain(
 ; CHECK-NEXT:    [[AND1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[AND2:%.*]] = and i1 [[AND1]], [[C:%.*]]
+; CHECK:         [[AND2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
+; CHECK:         [[AND2_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
+; CHECK:         [[AND1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND1]])
+; CHECK:         [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[B_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
+; CHECK:         [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
 ; CHECK-NEXT:    br i1 [[AND2]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
-; CHECK-NEXT:    call void @foo(i1 [[A]])
-; CHECK-NEXT:    call void @foo(i1 [[B]])
-; CHECK-NEXT:    call void @foo(i1 [[C]])
-; CHECK-NEXT:    call void @foo(i1 [[AND1]])
-; CHECK-NEXT:    call void @foo(i1 [[AND2]])
+; CHECK-NEXT:    call void @foo(i1 [[A_0]])
+; CHECK-NEXT:    call void @foo(i1 [[B_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C_0]])
+; CHECK-NEXT:    call void @foo(i1 [[AND1_0]])
+; CHECK-NEXT:    call void @foo(i1 [[AND2_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
 ; CHECK-NEXT:    call void @foo(i1 [[A]])
 ; CHECK-NEXT:    call void @foo(i1 [[B]])
 ; CHECK-NEXT:    call void @foo(i1 [[C]])
 ; CHECK-NEXT:    call void @foo(i1 [[AND1]])
-; CHECK-NEXT:    call void @foo(i1 [[AND2]])
+; CHECK-NEXT:    call void @foo(i1 [[AND2_1]])
 ; CHECK-NEXT:    ret void
 ;
   %and1 = and i1 %a, %b
@@ -329,20 +346,26 @@ define void @test_or_chain(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @test_or_chain(
 ; CHECK-NEXT:    [[OR1:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[OR2:%.*]] = or i1 [[OR1]], [[C:%.*]]
+; CHECK:         [[OR2_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
+; CHECK:         [[OR2_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
+; CHECK:         [[OR1_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR1]])
+; CHECK:         [[A_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[B_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
+; CHECK:         [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
 ; CHECK-NEXT:    br i1 [[OR2]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    call void @foo(i1 [[A]])
 ; CHECK-NEXT:    call void @foo(i1 [[B]])
 ; CHECK-NEXT:    call void @foo(i1 [[C]])
 ; CHECK-NEXT:    call void @foo(i1 [[OR1]])
-; CHECK-NEXT:    call void @foo(i1 [[OR2]])
+; CHECK-NEXT:    call void @foo(i1 [[OR2_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
-; CHECK-NEXT:    call void @foo(i1 [[A]])
-; CHECK-NEXT:    call void @foo(i1 [[B]])
-; CHECK-NEXT:    call void @foo(i1 [[C]])
-; CHECK-NEXT:    call void @foo(i1 [[OR1]])
-; CHECK-NEXT:    call void @foo(i1 [[OR2]])
+; CHECK-NEXT:    call void @foo(i1 [[A_0]])
+; CHECK-NEXT:    call void @foo(i1 [[B_0]])
+; CHECK-NEXT:    call void @foo(i1 [[C_0]])
+; CHECK-NEXT:    call void @foo(i1 [[OR1_0]])
+; CHECK-NEXT:    call void @foo(i1 [[OR2_1]])
 ; CHECK-NEXT:    ret void
 ;
   %or1 = or i1 %a, %b
@@ -370,20 +393,24 @@ define void @test_and_or_mixed(i1 %a, i1 %b, i1 %c) {
 ; CHECK-LABEL: @test_and_or_mixed(
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[OR]], [[C:%.*]]
+; CHECK:         [[AND_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND]])
+; CHECK:         [[AND_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND]])
+; CHECK:         [[OR_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR]])
+; CHECK:         [[C_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
 ; CHECK-NEXT:    br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    call void @foo(i1 [[A]])
 ; CHECK-NEXT:    call void @foo(i1 [[B]])
-; CHECK-NEXT:    call void @foo(i1 [[C]])
-; CHECK-NEXT:    call void @foo(i1 [[OR]])
-; CHECK-NEXT:    call void @foo(i1 [[AND]])
+; CHECK-NEXT:    call void @foo(i1 [[C_0]])
+; CHECK-NEXT:    call void @foo(i1 [[OR_0]])
+; CHECK-NEXT:    call void @foo(i1 [[AND_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
 ; CHECK-NEXT:    call void @foo(i1 [[A]])
 ; CHECK-NEXT:    call void @foo(i1 [[B]])
 ; CHECK-NEXT:    call void @foo(i1 [[C]])
 ; CHECK-NEXT:    call void @foo(i1 [[OR]])
-; CHECK-NEXT:    call void @foo(i1 [[AND]])
+; CHECK-NEXT:    call void @foo(i1 [[AND_1]])
 ; CHECK-NEXT:    ret void
 ;
   %or = or i1 %a, %b
@@ -423,31 +450,38 @@ define void @test_deep_and_chain(i1 %a1) {
 ; CHECK-NEXT:    [[A13:%.*]] = and i1 [[A12]], true
 ; CHECK-NEXT:    [[A14:%.*]] = and i1 [[A13]], true
 ; CHECK-NEXT:    [[A15:%.*]] = and i1 [[A14]], true
+; CHECK:         [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
+; CHECK:         [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
+; CHECK:         [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
+; CHECK:         [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
+; CHECK:         [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
+; CHECK:         [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
+; CHECK:         [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
 ; CHECK-NEXT:    br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
-; CHECK-NEXT:    call void @foo(i1 [[A8]])
-; CHECK-NEXT:    call void @foo(i1 [[A9]])
-; CHECK-NEXT:    call void @foo(i1 [[A10]])
-; CHECK-NEXT:    call void @foo(i1 [[A11]])
-; CHECK-NEXT:    call void @foo(i1 [[A12]])
-; CHECK-NEXT:    call void @foo(i1 [[A13]])
-; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A8_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A9_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A10_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A11_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A12_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A13_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A14_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
@@ -458,7 +492,7 @@ define void @test_deep_and_chain(i1 %a1) {
 ; CHECK-NEXT:    call void @foo(i1 [[A12]])
 ; CHECK-NEXT:    call void @foo(i1 [[A13]])
 ; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_1]])
 ; CHECK-NEXT:    ret void
 ;
   %a2 = and i1 %a1, true
@@ -482,7 +516,6 @@ if:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -501,7 +534,6 @@ else:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -532,31 +564,38 @@ define void @test_deep_and_tree(i1 %a1) {
 ; CHECK-NEXT:    [[A13:%.*]] = and i1 [[A12]], [[A12]]
 ; CHECK-NEXT:    [[A14:%.*]] = and i1 [[A13]], [[A13]]
 ; CHECK-NEXT:    [[A15:%.*]] = and i1 [[A14]], [[A14]]
+; CHECK:         [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
+; CHECK:         [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
+; CHECK:         [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
+; CHECK:         [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
+; CHECK:         [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
+; CHECK:         [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
+; CHECK:         [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
 ; CHECK-NEXT:    br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
-; CHECK-NEXT:    call void @foo(i1 [[A8]])
-; CHECK-NEXT:    call void @foo(i1 [[A9]])
-; CHECK-NEXT:    call void @foo(i1 [[A10]])
-; CHECK-NEXT:    call void @foo(i1 [[A11]])
-; CHECK-NEXT:    call void @foo(i1 [[A12]])
-; CHECK-NEXT:    call void @foo(i1 [[A13]])
-; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A8_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A9_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A10_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A11_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A12_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A13_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A14_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
@@ -567,7 +606,7 @@ define void @test_deep_and_tree(i1 %a1) {
 ; CHECK-NEXT:    call void @foo(i1 [[A12]])
 ; CHECK-NEXT:    call void @foo(i1 [[A13]])
 ; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_1]])
 ; CHECK-NEXT:    ret void
 ;
   %a2 = and i1 %a1, %a1
@@ -591,7 +630,6 @@ if:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -610,7 +648,6 @@ else:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -641,13 +678,21 @@ define void @test_deep_or_tree(i1 %a1) {
 ; CHECK-NEXT:    [[A13:%.*]] = or i1 [[A12]], [[A12]]
 ; CHECK-NEXT:    [[A14:%.*]] = or i1 [[A13]], [[A13]]
 ; CHECK-NEXT:    [[A15:%.*]] = or i1 [[A14]], [[A14]]
+; CHECK:         [[A15_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A15_1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
+; CHECK:         [[A14_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
+; CHECK:         [[A13_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
+; CHECK:         [[A12_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
+; CHECK:         [[A11_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
+; CHECK:         [[A10_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
+; CHECK:         [[A9_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
+; CHECK:         [[A8_0:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
 ; CHECK-NEXT:    br i1 [[A15]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
@@ -658,25 +703,24 @@ define void @test_deep_or_tree(i1 %a1) {
 ; CHECK-NEXT:    call void @foo(i1 [[A12]])
 ; CHECK-NEXT:    call void @foo(i1 [[A13]])
 ; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       else:
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
-; CHECK-NEXT:    call void @foo(i1 [[A8]])
-; CHECK-NEXT:    call void @foo(i1 [[A9]])
-; CHECK-NEXT:    call void @foo(i1 [[A10]])
-; CHECK-NEXT:    call void @foo(i1 [[A11]])
-; CHECK-NEXT:    call void @foo(i1 [[A12]])
-; CHECK-NEXT:    call void @foo(i1 [[A13]])
-; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[A8_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A9_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A10_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A11_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A12_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A13_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A14_0]])
+; CHECK-NEXT:    call void @foo(i1 [[A15_1]])
 ; CHECK-NEXT:    ret void
 ;
   %a2 = or i1 %a1, %a1
@@ -700,7 +744,6 @@ if:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -719,7 +762,6 @@ else:
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)
@@ -739,11 +781,16 @@ define void @test_assume_and_chain(i1 %a, i1 %b, i1 %c) {
 ; CHECK-NEXT:    [[AND1:%.*]] = and i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[AND2:%.*]] = and i1 [[AND1]], [[C:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[AND2]])
-; CHECK-NEXT:    call void @foo(i1 [[A]])
-; CHECK-NEXT:    call void @foo(i1 [[B]])
-; CHECK-NEXT:    call void @foo(i1 [[C]])
-; CHECK-NEXT:    call void @foo(i1 [[AND1]])
-; CHECK-NEXT:    call void @foo(i1 [[AND2]])
+; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[C]])
+; CHECK:         [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[B]])
+; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A]])
+; CHECK:         [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND1]])
+; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[AND2]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP3]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP2]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP1]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP4]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP5]])
 ; CHECK-NEXT:    ret void
 ;
   %and1 = and i1 %a, %b
@@ -762,11 +809,12 @@ define void @test_assume_or_chain(i1 %a, i1 %b, i1 %c) {
 ; CHECK-NEXT:    [[OR1:%.*]] = or i1 [[A:%.*]], [[B:%.*]]
 ; CHECK-NEXT:    [[OR2:%.*]] = or i1 [[OR1]], [[C:%.*]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[OR2]])
+; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[OR2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A]])
 ; CHECK-NEXT:    call void @foo(i1 [[B]])
 ; CHECK-NEXT:    call void @foo(i1 [[C]])
 ; CHECK-NEXT:    call void @foo(i1 [[OR1]])
-; CHECK-NEXT:    call void @foo(i1 [[OR2]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP1]])
 ; CHECK-NEXT:    ret void
 ;
   %or1 = or i1 %a, %b
@@ -797,22 +845,29 @@ define void @test_assume_deep_and_tree(i1 %a1) {
 ; CHECK-NEXT:    [[A14:%.*]] = and i1 [[A13]], [[A13]]
 ; CHECK-NEXT:    [[A15:%.*]] = and i1 [[A14]], [[A14]]
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A15]])
+; CHECK:         [[TMP1:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A8]])
+; CHECK:         [[TMP2:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A9]])
+; CHECK:         [[TMP3:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A10]])
+; CHECK:         [[TMP4:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A11]])
+; CHECK:         [[TMP5:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A12]])
+; CHECK:         [[TMP6:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A13]])
+; CHECK:         [[TMP7:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A14]])
+; CHECK:         [[TMP8:%.*]] = call i1 @llvm.ssa.copy.{{.+}}(i1 [[A15]])
 ; CHECK-NEXT:    call void @foo(i1 [[A1]])
 ; CHECK-NEXT:    call void @foo(i1 [[A2]])
 ; CHECK-NEXT:    call void @foo(i1 [[A3]])
 ; CHECK-NEXT:    call void @foo(i1 [[A4]])
-; CHECK-NEXT:    call void @foo(i1 [[A4]])
 ; CHECK-NEXT:    call void @foo(i1 [[A5]])
 ; CHECK-NEXT:    call void @foo(i1 [[A6]])
 ; CHECK-NEXT:    call void @foo(i1 [[A7]])
-; CHECK-NEXT:    call void @foo(i1 [[A8]])
-; CHECK-NEXT:    call void @foo(i1 [[A9]])
-; CHECK-NEXT:    call void @foo(i1 [[A10]])
-; CHECK-NEXT:    call void @foo(i1 [[A11]])
-; CHECK-NEXT:    call void @foo(i1 [[A12]])
-; CHECK-NEXT:    call void @foo(i1 [[A13]])
-; CHECK-NEXT:    call void @foo(i1 [[A14]])
-; CHECK-NEXT:    call void @foo(i1 [[A15]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP1]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP2]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP3]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP4]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP5]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP6]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP7]])
+; CHECK-NEXT:    call void @foo(i1 [[TMP8]])
 ; CHECK-NEXT:    ret void
 ;
   %a2 = and i1 %a1, %a1
@@ -834,7 +889,6 @@ define void @test_assume_deep_and_tree(i1 %a1) {
   call void @foo(i1 %a2)
   call void @foo(i1 %a3)
   call void @foo(i1 %a4)
-  call void @foo(i1 %a4)
   call void @foo(i1 %a5)
   call void @foo(i1 %a6)
   call void @foo(i1 %a7)


        


More information about the llvm-branch-commits mailing list