[llvm] f8045b2 - Recommit "[SCCP] Remove forcedconstant, go to overdefined instead"

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 15 09:37:23 PST 2020


Author: Florian Hahn
Date: 2020-02-15T18:36:44+01:00
New Revision: f8045b250d80ccdb2ae5f46d3aa02137fe475907

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

LOG: Recommit "[SCCP] Remove forcedconstant, go to overdefined instead"

This includes a fix for cases where things get marked as overdefined in
ResolvedUndefsIn, but we later discover a constant. To avoid crashing,
we consistently bail out on overdefined values in the visitors. This is
similar to the previous behavior with forcedconstant.

This reverts the revert commit 02b72f564c8be0b4f4337d5c4a3fcf7e8018a818.

Added: 
    llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll

Modified: 
    llvm/lib/Transforms/Scalar/SCCP.cpp
    llvm/test/Transforms/IPConstantProp/PR16052.ll
    llvm/test/Transforms/IPConstantProp/PR26044.ll
    llvm/test/Transforms/SCCP/2006-12-19-UndefBug.ll
    llvm/test/Transforms/SCCP/apint-bigint2.ll
    llvm/test/Transforms/SCCP/apint-ipsccp3.ll
    llvm/test/Transforms/SCCP/apint-select.ll
    llvm/test/Transforms/SCCP/ip-constant-ranges.ll
    llvm/test/Transforms/SCCP/ipsccp-basic.ll
    llvm/test/Transforms/SCCP/logical-nuke.ll
    llvm/test/Transforms/SCCP/switch-multiple-undef.ll
    llvm/test/Transforms/SCCP/ub-shift.ll
    llvm/test/Transforms/SCCP/undef-resolve.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 34f18ec7c121..e0c7bb8868a6 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -85,19 +85,13 @@ class LatticeVal {
     /// constant - This LLVM Value has a specific constant value.
     constant,
 
-    /// forcedconstant - This LLVM Value was thought to be undef until
-    /// ResolvedUndefsIn.  This is treated just like 'constant', but if merged
-    /// with another (
diff erent) constant, it goes to overdefined, instead of
-    /// asserting.
-    forcedconstant,
-
     /// overdefined - This instruction is not known to be constant, and we know
     /// it has a value.
     overdefined
   };
 
   /// Val: This stores the current lattice value along with the Constant* for
-  /// the constant if this is a 'constant' or 'forcedconstant' value.
+  /// the constant if this is a 'constant' value.
   PointerIntPair<Constant *, 2, LatticeValueTy> Val;
 
   LatticeValueTy getLatticeValue() const {
@@ -109,9 +103,7 @@ class LatticeVal {
 
   bool isUnknown() const { return getLatticeValue() == unknown; }
 
-  bool isConstant() const {
-    return getLatticeValue() == constant || getLatticeValue() == forcedconstant;
-  }
+  bool isConstant() const { return getLatticeValue() == constant; }
 
   bool isOverdefined() const { return getLatticeValue() == overdefined; }
 
@@ -131,26 +123,15 @@ class LatticeVal {
 
   /// markConstant - Return true if this is a change in status.
   bool markConstant(Constant *V) {
-    if (getLatticeValue() == constant) { // Constant but not forcedconstant.
+    if (getLatticeValue() == constant) { // Constant
       assert(getConstant() == V && "Marking constant with 
diff erent value");
       return false;
     }
 
-    if (isUnknown()) {
-      Val.setInt(constant);
-      assert(V && "Marking constant with NULL");
-      Val.setPointer(V);
-    } else {
-      assert(getLatticeValue() == forcedconstant &&
-             "Cannot move from overdefined to constant!");
-      // Stay at forcedconstant if the constant is the same.
-      if (V == getConstant()) return false;
-
-      // Otherwise, we go to overdefined.  Assumptions made based on the
-      // forced value are possibly wrong.  Assuming this is another constant
-      // could expose a contradiction.
-      Val.setInt(overdefined);
-    }
+    assert(isUnknown());
+    Val.setInt(constant);
+    assert(V && "Marking constant with NULL");
+    Val.setPointer(V);
     return true;
   }
 
@@ -170,12 +151,6 @@ class LatticeVal {
     return nullptr;
   }
 
-  void markForcedConstant(Constant *V) {
-    assert(isUnknown() && "Can't force a defined value!");
-    Val.setInt(forcedconstant);
-    Val.setPointer(V);
-  }
-
   ValueLatticeElement toValueLattice() const {
     if (isOverdefined())
       return ValueLatticeElement::getOverdefined();
@@ -421,7 +396,7 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
   }
 
 private:
-  // pushToWorkList - Helper for markConstant/markForcedConstant/markOverdefined
+  // pushToWorkList - Helper for markConstant/markOverdefined
   void pushToWorkList(LatticeVal &IV, Value *V) {
     if (IV.isOverdefined())
       return OverdefinedInstWorkList.push_back(V);
@@ -443,14 +418,6 @@ class SCCPSolver : public InstVisitor<SCCPSolver> {
     return markConstant(ValueState[V], V, C);
   }
 
-  void markForcedConstant(Value *V, Constant *C) {
-    assert(!V->getType()->isStructTy() && "structs should use mergeInValue");
-    LatticeVal &IV = ValueState[V];
-    IV.markForcedConstant(C);
-    LLVM_DEBUG(dbgs() << "markForcedConstant: " << *C << ": " << *V << '\n');
-    pushToWorkList(IV, V);
-  }
-
   // markOverdefined - Make a value be marked as "overdefined". If the
   // value is not already overdefined, add it to the overdefined instruction
   // work list so that the users of the instruction are updated later.
@@ -853,6 +820,11 @@ void SCCPSolver::visitPHINode(PHINode &PN) {
 void SCCPSolver::visitReturnInst(ReturnInst &I) {
   if (I.getNumOperands() == 0) return;  // ret void
 
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&I].isOverdefined())
+    return;
+
   Function *F = I.getParent()->getParent();
   Value *ResultOp = I.getOperand(0);
 
@@ -889,6 +861,11 @@ void SCCPSolver::visitTerminator(Instruction &TI) {
 }
 
 void SCCPSolver::visitCastInst(CastInst &I) {
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&I].isOverdefined())
+    return;
+
   LatticeVal OpSt = getValueState(I.getOperand(0));
   if (OpSt.isOverdefined())          // Inherit overdefinedness of operand
     markOverdefined(&I);
@@ -904,6 +881,11 @@ void SCCPSolver::visitCastInst(CastInst &I) {
 }
 
 void SCCPSolver::visitExtractValueInst(ExtractValueInst &EVI) {
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&EVI].isOverdefined())
+    return;
+
   // If this returns a struct, mark all elements over defined, we don't track
   // structs in structs.
   if (EVI.getType()->isStructTy())
@@ -929,6 +911,11 @@ void SCCPSolver::visitInsertValueInst(InsertValueInst &IVI) {
   if (!STy)
     return (void)markOverdefined(&IVI);
 
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&IVI].isOverdefined())
+    return;
+
   // If this has more than one index, we can't handle it, drive all results to
   // undef.
   if (IVI.getNumIndices() != 1)
@@ -963,6 +950,11 @@ void SCCPSolver::visitSelectInst(SelectInst &I) {
   if (I.getType()->isStructTy())
     return (void)markOverdefined(&I);
 
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&I].isOverdefined())
+    return;
+
   LatticeVal CondValue = getValueState(I.getCondition());
   if (CondValue.isUnknown())
     return;
@@ -996,6 +988,8 @@ void SCCPSolver::visitUnaryOperator(Instruction &I) {
   LatticeVal V0State = getValueState(I.getOperand(0));
 
   LatticeVal &IV = ValueState[&I];
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
   if (IV.isOverdefined()) return;
 
   if (V0State.isConstant()) {
@@ -1032,8 +1026,10 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
   }
 
   // If something is undef, wait for it to resolve.
-  if (!V1State.isOverdefined() && !V2State.isOverdefined())
+  if (!V1State.isOverdefined() && !V2State.isOverdefined()) {
+
     return;
+  }
 
   // Otherwise, one of our operands is overdefined.  Try to produce something
   // better than overdefined with some tricks.
@@ -1054,7 +1050,6 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
       NonOverdefVal = &V1State;
     else if (!V2State.isOverdefined())
       NonOverdefVal = &V2State;
-
     if (NonOverdefVal) {
       if (NonOverdefVal->isUnknown())
         return;
@@ -1153,6 +1148,11 @@ void SCCPSolver::visitStoreInst(StoreInst &SI) {
   if (TrackedGlobals.empty() || !isa<GlobalVariable>(SI.getOperand(1)))
     return;
 
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&SI].isOverdefined())
+    return;
+
   GlobalVariable *GV = cast<GlobalVariable>(SI.getOperand(1));
   DenseMap<GlobalVariable*, LatticeVal>::iterator I = TrackedGlobals.find(GV);
   if (I == TrackedGlobals.end() || I->second.isOverdefined()) return;
@@ -1170,11 +1170,15 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
   if (I.getType()->isStructTy())
     return (void)markOverdefined(&I);
 
+  // ResolvedUndefsIn might mark I as overdefined. Bail out, even if we would
+  // discover a concrete value later.
+  if (ValueState[&I].isOverdefined())
+    return;
+
   LatticeVal PtrVal = getValueState(I.getOperand(0));
   if (PtrVal.isUnknown()) return;   // The pointer is not resolved yet!
 
   LatticeVal &IV = ValueState[&I];
-  if (IV.isOverdefined()) return;
 
   if (!PtrVal.isConstant() || I.isVolatile())
     return (void)markOverdefined(IV, &I);
@@ -1449,10 +1453,8 @@ void SCCPSolver::Solve() {
 /// constraints on the condition of the branch, as that would impact other users
 /// of the value.
 ///
-/// This scan also checks for values that use undefs, whose results are actually
-/// defined.  For example, 'zext i8 undef to i32' should produce all zeros
-/// conservatively, as "(zext i8 X -> i32) & 0xFF00" must always return zero,
-/// even if X isn't defined.
+/// This scan also checks for values that use undefs. It conservatively marks
+/// them as overdefined.
 bool SCCPSolver::ResolvedUndefsIn(Function &F) {
   for (BasicBlock &BB : F) {
     if (!BBExecutable.count(&BB))
@@ -1475,7 +1477,6 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
         // tracked as precisely as their operands.
         if (isa<ExtractValueInst>(I) || isa<InsertValueInst>(I))
           continue;
-
         // Send the results of everything else to overdefined.  We could be
         // more precise than this but it isn't worth bothering.
         for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
@@ -1495,195 +1496,13 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
       // 2. It could be constant-foldable.
       // Because of the way we solve return values, tracked calls must
       // never be marked overdefined in ResolvedUndefsIn.
-      if (CallSite CS = CallSite(&I)) {
+      if (CallSite CS = CallSite(&I))
         if (Function *F = CS.getCalledFunction())
           if (TrackedRetVals.count(F))
             continue;
 
-        // If the call is constant-foldable, we mark it overdefined because
-        // we do not know what return values are valid.
-        markOverdefined(&I);
-        return true;
-      }
-
-      // extractvalue is safe; check here because the argument is a struct.
-      if (isa<ExtractValueInst>(I))
-        continue;
-
-      // Compute the operand LatticeVals, for convenience below.
-      // Anything taking a struct is conservatively assumed to require
-      // overdefined markings.
-      if (I.getOperand(0)->getType()->isStructTy()) {
-        markOverdefined(&I);
-        return true;
-      }
-      LatticeVal Op0LV = getValueState(I.getOperand(0));
-      LatticeVal Op1LV;
-      if (I.getNumOperands() == 2) {
-        if (I.getOperand(1)->getType()->isStructTy()) {
-          markOverdefined(&I);
-          return true;
-        }
-
-        Op1LV = getValueState(I.getOperand(1));
-      }
-      // If this is an instructions whose result is defined even if the input is
-      // not fully defined, propagate the information.
-      Type *ITy = I.getType();
-      switch (I.getOpcode()) {
-      case Instruction::Add:
-      case Instruction::Sub:
-      case Instruction::Trunc:
-      case Instruction::FPTrunc:
-      case Instruction::BitCast:
-        break; // Any undef -> undef
-      case Instruction::FSub:
-      case Instruction::FAdd:
-      case Instruction::FMul:
-      case Instruction::FDiv:
-      case Instruction::FRem:
-        // Floating-point binary operation: be conservative.
-        if (Op0LV.isUnknown() && Op1LV.isUnknown())
-          markForcedConstant(&I, Constant::getNullValue(ITy));
-        else
-          markOverdefined(&I);
-        return true;
-      case Instruction::FNeg:
-        break; // fneg undef -> undef
-      case Instruction::ZExt:
-      case Instruction::SExt:
-      case Instruction::FPToUI:
-      case Instruction::FPToSI:
-      case Instruction::FPExt:
-      case Instruction::PtrToInt:
-      case Instruction::IntToPtr:
-      case Instruction::SIToFP:
-      case Instruction::UIToFP:
-        // undef -> 0; some outputs are impossible
-        markForcedConstant(&I, Constant::getNullValue(ITy));
-        return true;
-      case Instruction::Mul:
-      case Instruction::And:
-        // Both operands undef -> undef
-        if (Op0LV.isUnknown() && Op1LV.isUnknown())
-          break;
-        // undef * X -> 0.   X could be zero.
-        // undef & X -> 0.   X could be zero.
-        markForcedConstant(&I, Constant::getNullValue(ITy));
-        return true;
-      case Instruction::Or:
-        // Both operands undef -> undef
-        if (Op0LV.isUnknown() && Op1LV.isUnknown())
-          break;
-        // undef | X -> -1.   X could be -1.
-        markForcedConstant(&I, Constant::getAllOnesValue(ITy));
-        return true;
-      case Instruction::Xor:
-        // undef ^ undef -> 0; strictly speaking, this is not strictly
-        // necessary, but we try to be nice to people who expect this
-        // behavior in simple cases
-        if (Op0LV.isUnknown() && Op1LV.isUnknown()) {
-          markForcedConstant(&I, Constant::getNullValue(ITy));
-          return true;
-        }
-        // undef ^ X -> undef
-        break;
-      case Instruction::SDiv:
-      case Instruction::UDiv:
-      case Instruction::SRem:
-      case Instruction::URem:
-        // X / undef -> undef.  No change.
-        // X % undef -> undef.  No change.
-        if (Op1LV.isUnknown()) break;
-
-        // X / 0 -> undef.  No change.
-        // X % 0 -> undef.  No change.
-        if (Op1LV.isConstant() && Op1LV.getConstant()->isZeroValue())
-          break;
-
-        // undef / X -> 0.   X could be maxint.
-        // undef % X -> 0.   X could be 1.
-        markForcedConstant(&I, Constant::getNullValue(ITy));
-        return true;
-      case Instruction::AShr:
-        // X >>a undef -> undef.
-        if (Op1LV.isUnknown()) break;
-
-        // Shifting by the bitwidth or more is undefined.
-        if (Op1LV.isConstant()) {
-          if (auto *ShiftAmt = Op1LV.getConstantInt())
-            if (ShiftAmt->getLimitedValue() >=
-                ShiftAmt->getType()->getScalarSizeInBits())
-              break;
-        }
-
-        // undef >>a X -> 0
-        markForcedConstant(&I, Constant::getNullValue(ITy));
-        return true;
-      case Instruction::LShr:
-      case Instruction::Shl:
-        // X << undef -> undef.
-        // X >> undef -> undef.
-        if (Op1LV.isUnknown()) break;
-
-        // Shifting by the bitwidth or more is undefined.
-        if (Op1LV.isConstant()) {
-          if (auto *ShiftAmt = Op1LV.getConstantInt())
-            if (ShiftAmt->getLimitedValue() >=
-                ShiftAmt->getType()->getScalarSizeInBits())
-              break;
-        }
-
-        // undef << X -> 0
-        // undef >> X -> 0
-        markForcedConstant(&I, Constant::getNullValue(ITy));
-        return true;
-      case Instruction::Select:
-        Op1LV = getValueState(I.getOperand(1));
-        // undef ? X : Y  -> X or Y.  There could be commonality between X/Y.
-        if (Op0LV.isUnknown()) {
-          if (!Op1LV.isConstant())  // Pick the constant one if there is any.
-            Op1LV = getValueState(I.getOperand(2));
-        } else if (Op1LV.isUnknown()) {
-          // c ? undef : undef -> undef.  No change.
-          Op1LV = getValueState(I.getOperand(2));
-          if (Op1LV.isUnknown())
-            break;
-          // Otherwise, c ? undef : x -> x.
-        } else {
-          // Leave Op1LV as Operand(1)'s LatticeValue.
-        }
-
-        if (Op1LV.isConstant())
-          markForcedConstant(&I, Op1LV.getConstant());
-        else
-          markOverdefined(&I);
-        return true;
-      case Instruction::Load:
-        // A load here means one of two things: a load of undef from a global,
-        // a load from an unknown pointer.  Either way, having it return undef
-        // is okay.
-        break;
-      case Instruction::ICmp:
-        // X == undef -> undef.  Other comparisons get more complicated.
-        Op0LV = getValueState(I.getOperand(0));
-        Op1LV = getValueState(I.getOperand(1));
-
-        if ((Op0LV.isUnknown() || Op1LV.isUnknown()) &&
-            cast<ICmpInst>(&I)->isEquality())
-          break;
-        markOverdefined(&I);
-        return true;
-      case Instruction::Call:
-      case Instruction::Invoke:
-      case Instruction::CallBr:
-        llvm_unreachable("Call-like instructions should have be handled early");
-      default:
-        // If we don't know what should happen here, conservatively mark it
-        // overdefined.
-        markOverdefined(&I);
-        return true;
-      }
+      markOverdefined(&I);
+      return true;
     }
 
     // Check to see if we have a branch or switch on an undefined value.  If so

diff  --git a/llvm/test/Transforms/IPConstantProp/PR16052.ll b/llvm/test/Transforms/IPConstantProp/PR16052.ll
index 451693f1c90c..a16067fe278a 100644
--- a/llvm/test/Transforms/IPConstantProp/PR16052.ll
+++ b/llvm/test/Transforms/IPConstantProp/PR16052.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
 ; RUN: opt < %s -S -ipsccp | FileCheck %s
 
 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
@@ -7,7 +7,9 @@ target triple = "x86_64-unknown-linux-gnu"
 define i64 @fn2() {
 ; CHECK-LABEL: define {{[^@]+}}@fn2()
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[CALL2:%.*]] = call i64 @fn1(i64 undef)
+; CHECK-NEXT:    [[CONV:%.*]] = sext i32 undef to i64
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; CHECK-NEXT:    [[CALL2:%.*]] = call i64 @fn1(i64 [[DIV]])
 ; CHECK-NEXT:    ret i64 [[CALL2]]
 ;
 entry:
@@ -21,7 +23,8 @@ define internal i64 @fn1(i64 %p1) {
 ; CHECK-LABEL: define {{[^@]+}}@fn1
 ; CHECK-SAME: (i64 [[P1:%.*]])
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[COND:%.*]] = select i1 undef, i64 undef, i64 undef
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i64 [[P1]], 0
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[P1]], i64 [[P1]]
 ; CHECK-NEXT:    ret i64 [[COND]]
 ;
 entry:

diff  --git a/llvm/test/Transforms/IPConstantProp/PR26044.ll b/llvm/test/Transforms/IPConstantProp/PR26044.ll
index eeb5b87e0a28..8b4f2590b9f8 100644
--- a/llvm/test/Transforms/IPConstantProp/PR26044.ll
+++ b/llvm/test/Transforms/IPConstantProp/PR26044.ll
@@ -11,7 +11,8 @@ define void @fn2(i32* %P) {
 ; CHECK:       for.cond1:
 ; CHECK-NEXT:    br i1 false, label [[IF_END]], label [[IF_END]]
 ; CHECK:       if.end:
-; CHECK-NEXT:    [[CALL:%.*]] = call i32 @fn1(i32 undef)
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* null, align 4
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @fn1(i32 [[TMP0]])
 ; CHECK-NEXT:    store i32 [[CALL]], i32* [[P]]
 ; CHECK-NEXT:    br label [[FOR_COND1:%.*]]
 ;
@@ -33,7 +34,8 @@ define internal i32 @fn1(i32 %p1) {
 ; CHECK-LABEL: define {{[^@]+}}@fn1
 ; CHECK-SAME: (i32 [[P1:%.*]])
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[COND:%.*]] = select i1 undef, i32 undef, i32 undef
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[P1]], 0
+; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[P1]], i32 [[P1]]
 ; CHECK-NEXT:    ret i32 [[COND]]
 ;
 entry:

diff  --git a/llvm/test/Transforms/SCCP/2006-12-19-UndefBug.ll b/llvm/test/Transforms/SCCP/2006-12-19-UndefBug.ll
index ede1a32c5f7a..4bd096e0a656 100644
--- a/llvm/test/Transforms/SCCP/2006-12-19-UndefBug.ll
+++ b/llvm/test/Transforms/SCCP/2006-12-19-UndefBug.ll
@@ -1,8 +1,12 @@
-; RUN: opt < %s -sccp -S | \
-; RUN:   grep "ret i1 false"
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -sccp -S | FileCheck %s
 
 define i1 @foo() {
-	%X = and i1 false, undef		; <i1> [#uses=1]
-	ret i1 %X
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[X:%.*]] = and i1 false, undef
+; CHECK-NEXT:    ret i1 [[X]]
+;
+  %X = and i1 false, undef		; <i1> [#uses=1]
+  ret i1 %X
 }
 

diff  --git a/llvm/test/Transforms/SCCP/apint-bigint2.ll b/llvm/test/Transforms/SCCP/apint-bigint2.ll
index 5277d9fa5c6e..7d75240a0d8e 100644
--- a/llvm/test/Transforms/SCCP/apint-bigint2.ll
+++ b/llvm/test/Transforms/SCCP/apint-bigint2.ll
@@ -18,7 +18,13 @@ define i101 @array() {
 }
 
 ; CHECK-LABEL: @large_aggregate
-; CHECK-NEXT: ret i101 undef
+; CHECK-NEXT:    %B = load i101, i101* undef
+; CHECK-NEXT:    %D = and i101 %B, 1
+; CHECK-NEXT:    %DD = or i101 %D, 1
+; CHECK-NEXT:    %G = getelementptr i101, i101* getelementptr inbounds ([6 x i101], [6 x i101]* @Y, i32 0, i32 5), i101 %DD
+; CHECK-NEXT:    %L3 = load i101, i101* %G
+; CHECK-NEXT:    ret i101 %L3
+;
 define i101 @large_aggregate() {
   %B = load i101, i101* undef
   %D = and i101 %B, 1
@@ -29,6 +35,22 @@ define i101 @large_aggregate() {
   ret i101 %L3
 }
 
+; CHECK-LABEL: define i101 @large_aggregate_2() {
+; CHECK-NEXT:     %D = and i101 undef, 1
+; CHECK-NEXT:     %DD = or i101 %D, 1
+; CHECK-NEXT:     %G = getelementptr i101, i101* getelementptr inbounds ([6 x i101], [6 x i101]* @Y, i32 0, i32 5), i101 %DD
+; CHECK-NEXT:     %L3 = load i101, i101* %G
+; CHECK-NEXT:     ret i101 %L3
+;
+define i101 @large_aggregate_2() {
+  %D = and i101 undef, 1
+  %DD = or i101 %D, 1
+  %F = getelementptr [6 x i101], [6 x i101]* @Y, i32 0, i32 5
+  %G = getelementptr i101, i101* %F, i101 %DD
+  %L3 = load i101, i101* %G
+  ret i101 %L3
+}
+
 ; CHECK-LABEL: @index_too_large
 ; CHECK-NEXT: store i101* getelementptr (i101, i101* getelementptr ([6 x i101], [6 x i101]* @Y, i32 0, i32 -1), i101 9224497936761618431), i101** undef
 ; CHECK-NEXT: ret void

diff  --git a/llvm/test/Transforms/SCCP/apint-ipsccp3.ll b/llvm/test/Transforms/SCCP/apint-ipsccp3.ll
index c99ae5820b2d..4ba1f8db30ba 100644
--- a/llvm/test/Transforms/SCCP/apint-ipsccp3.ll
+++ b/llvm/test/Transforms/SCCP/apint-ipsccp3.ll
@@ -1,23 +1,39 @@
-; RUN: opt < %s -ipsccp -S | not grep global
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -ipsccp -S | FileCheck %s
 
 @G = internal global i66 undef
 
 
-
 define void @foo() {
-	%X = load i66, i66* @G
-	store i66 %X, i66* @G
-	ret void
+; CHECK-LABEL: @foo(
+; CHECK-NEXT:    [[X:%.*]] = load i66, i66* @G
+; CHECK-NEXT:    store i66 [[X]], i66* @G
+; CHECK-NEXT:    ret void
+;
+  %X = load i66, i66* @G
+  store i66 %X, i66* @G
+  ret void
 }
 
 define i66 @bar() {
-	%V = load i66, i66* @G
-	%C = icmp eq i66 %V, 17
-	br i1 %C, label %T, label %F
+; CHECK-LABEL: @bar(
+; CHECK-NEXT:    [[V:%.*]] = load i66, i66* @G
+; CHECK-NEXT:    [[C:%.*]] = icmp eq i66 [[V]], 17
+; CHECK-NEXT:    br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       T:
+; CHECK-NEXT:    store i66 17, i66* @G
+; CHECK-NEXT:    ret i66 17
+; CHECK:       F:
+; CHECK-NEXT:    store i66 123, i66* @G
+; CHECK-NEXT:    ret i66 0
+;
+  %V = load i66, i66* @G
+  %C = icmp eq i66 %V, 17
+  br i1 %C, label %T, label %F
 T:
-	store i66 17, i66* @G
-	ret i66 %V
+  store i66 17, i66* @G
+  ret i66 %V
 F:
-	store i66 123, i66* @G
-	ret i66 0
+  store i66 123, i66* @G
+  ret i66 0
 }

diff  --git a/llvm/test/Transforms/SCCP/apint-select.ll b/llvm/test/Transforms/SCCP/apint-select.ll
index 893331ea9867..d797c7a4d43c 100644
--- a/llvm/test/Transforms/SCCP/apint-select.ll
+++ b/llvm/test/Transforms/SCCP/apint-select.ll
@@ -1,21 +1,29 @@
-; RUN: opt < %s -sccp -S | not grep select
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -sccp -S | FileCheck %s
 
 @A = constant i32 10
 
 define i712 @test1() {
-        %P = getelementptr i32, i32* @A, i32 0
-        %B = ptrtoint i32* %P to i64
-        %BB = and i64 %B, undef
-        %C = icmp sge i64 %BB, 0
-	%X = select i1 %C, i712 0, i712 1
-	ret i712 %X
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[BB:%.*]] = and i64 ptrtoint (i32* @A to i64), undef
+; CHECK-NEXT:    [[C:%.*]] = icmp sge i64 [[BB]], 0
+; CHECK-NEXT:    [[X:%.*]] = select i1 [[C]], i712 0, i712 1
+; CHECK-NEXT:    ret i712 [[X]]
+;
+  %P = getelementptr i32, i32* @A, i32 0
+  %B = ptrtoint i32* %P to i64
+  %BB = and i64 %B, undef
+  %C = icmp sge i64 %BB, 0
+  %X = select i1 %C, i712 0, i712 1
+  ret i712 %X
 }
 
 
 
 define i712 @test2(i1 %C) {
-	%X = select i1 %C, i712 0, i712 undef
-	ret i712 %X
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i712 0
+;
+  %X = select i1 %C, i712 0, i712 undef
+  ret i712 %X
 }
-
-

diff  --git a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
index 426e3279661f..08de8dba4046 100644
--- a/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
+++ b/llvm/test/Transforms/SCCP/ip-constant-ranges.ll
@@ -141,10 +141,12 @@ define double @test_struct({ double, double } %test) {
 ; Constant range for %x is [47, 302)
 ; CHECK-LABEL: @f5
 ; CHECK-NEXT: entry:
-; CHECK-NEXT: %cmp = icmp sgt i32 %x, undef
-; CHECK-NEXT: %res1 = select i1 %cmp, i32 1, i32 2
-; CHECK-NEXT: %res = add i32 %res1, 3
-; CHECK-NEXT: ret i32 %res
+; CHECK-NEXT:   %cmp = icmp sgt i32 %x, undef
+; CHECK-NEXT:   %cmp2 = icmp ne i32 undef, %x
+; CHECK-NEXT:   %res1 = select i1 %cmp, i32 1, i32 2
+; CHECK-NEXT:   %res2 = select i1 %cmp2, i32 3, i32 4
+; CHECK-NEXT:   %res = add i32 %res1, %res2
+; CHECK-NEXT:   ret i32 %res
 define internal i32 @f5(i32 %x) {
 entry:
   %cmp = icmp sgt i32 %x, undef

diff  --git a/llvm/test/Transforms/SCCP/ipsccp-basic.ll b/llvm/test/Transforms/SCCP/ipsccp-basic.ll
index b1660b545652..795a73f1d907 100644
--- a/llvm/test/Transforms/SCCP/ipsccp-basic.ll
+++ b/llvm/test/Transforms/SCCP/ipsccp-basic.ll
@@ -56,7 +56,9 @@ define void @test3a() {
 	ret void
 }
 ; CHECK-LABEL: define void @test3a(
-; CHECK-NEXT: ret void
+; CHECK-NEXT:    %X = load i32, i32* @G
+; CHECK-NEXT:    store i32 %X, i32* @G
+; CHECK-NEXT:   ret void
 
 
 define i32 @test3b() {
@@ -71,9 +73,17 @@ F:
 	ret i32 0
 }
 ; CHECK-LABEL: define i32 @test3b(
-; CHECK-NOT: store
-; CHECK: ret i32 0
+; CHECK-NEXT:    %V = load i32, i32* @G
+; CHECK-NEXT:    %C = icmp eq i32 %V, 17
+; CHECK-NEXT:    br i1 %C, label %T, label %F
+
+; CHECK-LABEL: T:
+; CHECK-NEXT:   store i32 17, i32* @G
+; CHECK-NEXT:   ret i32 17
 
+; CHECK-LABEL: F:
+; CHECK-NEXT:    store i32 123, i32* @G
+; CHECK-NEXT:    ret i32 0
 
 ;;======================== test4
 
@@ -226,8 +236,11 @@ define i32 @test10a() nounwind {
 entry:
   %call = call i32 @test10b(i32 undef)
   ret i32 %call
+
 ; CHECK-LABEL: define i32 @test10a(
-; CHECK: ret i32 0
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    %call = call i32 @test10b(i32 undef)
+; CHECK-NEXT:    ret i32 %call
 }
 
 define internal i32 @test10b(i32 %x) nounwind {
@@ -235,7 +248,9 @@ entry:
   %r = and i32 %x, 1
   ret i32 %r
 ; CHECK-LABEL: define internal i32 @test10b(
-; CHECK: ret i32 undef
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    %r = and i32 undef, 1
+; CHECK-NEXT:    ret i32 %r
 }
 
 ;;======================== test11
@@ -244,7 +259,8 @@ define i64 @test11a() {
   %xor = xor i64 undef, undef
   ret i64 %xor
 ; CHECK-LABEL: define i64 @test11a
-; CHECK: ret i64 0
+; CHECK-NEXT:    %xor = xor i64 undef, undef
+; CHECK-NEXT:    ret i64 %xor
 }
 
 define i64 @test11b() {
@@ -252,9 +268,9 @@ define i64 @test11b() {
   %call2 = call i64 @llvm.ctpop.i64(i64 %call1)
   ret i64 %call2
 ; CHECK-LABEL: define i64 @test11b
-; CHECK: %[[call1:.*]] = call i64 @test11a()
-; CHECK-NOT: call i64 @llvm.ctpop.i64
-; CHECK-NEXT: ret i64 0
+; CHECK-NEXT:   [[call1:%.*]] = call i64 @test11a()
+; CHECK-NEXT:    [[call2:%.*]] = call i64 @llvm.ctpop.i64(i64 [[call1]])
+; CHECK-NEXT: ret i64 [[call2]]
 }
 
 declare i64 @llvm.ctpop.i64(i64)

diff  --git a/llvm/test/Transforms/SCCP/logical-nuke.ll b/llvm/test/Transforms/SCCP/logical-nuke.ll
index 6ca16de4489b..5152e126e8fa 100644
--- a/llvm/test/Transforms/SCCP/logical-nuke.ll
+++ b/llvm/test/Transforms/SCCP/logical-nuke.ll
@@ -1,39 +1,47 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -sccp -S | FileCheck %s
 
 ; Test that SCCP has basic knowledge of when and/or/mul nuke overdefined values.
 
-; CHECK-LABEL: test
-; CHECK: ret i32 0
  define i32 @test(i32 %X) {
+; CHECK-LABEL: @test(
+; CHECK-NEXT:    ret i32 0
+;
   %Y = and i32 %X, 0
   ret i32 %Y
 }
 
-; CHECK-LABEL: test2
-; CHECK: ret i32 -1
 define i32 @test2(i32 %X) {
+; CHECK-LABEL: @test2(
+; CHECK-NEXT:    ret i32 -1
+;
   %Y = or i32 -1, %X
   ret i32 %Y
 }
 
-; CHECK-LABEL: test3
-; CHECK: ret i32 0
 define i32 @test3(i32 %X) {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[Y:%.*]] = and i32 undef, [[X:%.*]]
+; CHECK-NEXT:    ret i32 [[Y]]
+;
   %Y = and i32 undef, %X
   ret i32 %Y
 }
 
-; CHECK-LABEL: test4
-; CHECK: ret i32 -1
 define i32 @test4(i32 %X) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[Y:%.*]] = or i32 [[X:%.*]], undef
+; CHECK-NEXT:    ret i32 [[Y]]
+;
   %Y = or i32 %X, undef
   ret i32 %Y
 }
 
 ; X * 0 = 0 even if X is overdefined.
-; CHECK-LABEL: test5
-; CHECK: ret i32 0
 define i32 @test5(i32 %foo) {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    ret i32 0
+;
   %patatino = mul i32 %foo, 0
   ret i32 %patatino
 }

diff  --git a/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll b/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
new file mode 100644
index 000000000000..c426674f6798
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
@@ -0,0 +1,418 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -ipsccp -S %s | FileCheck %s
+
+%t1 = type opaque
+
+ at e = common global i32 0, align 4
+
+; Test that we a skip unknown values depending on a unknown tracked call, until the call gets resolved. The @test1 and @test2 variants are very similar, they just check 2 
diff erent kinds of users (icmp and zext)
+
+define i32 @test1_m(i32 %h) {
+; CHECK-LABEL: define i32 @test1_m(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H:%.*]] to i8
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test1_k(i8 [[CONV]], i32 0)
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to %t1*
+; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test1_g(%t1* [[TMP0]], i32 1)
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %conv = trunc i32 %h to i8
+  %call = call i32 @test1_k(i8 %conv, i32 0)
+  %conv1 = sext i32 %h to i64
+  %0 = inttoptr i64 %conv1 to %t1*
+  %call2 = call i1 @test1_g(%t1* %0, i32 1)
+  ret i32 undef
+
+; uselistorder directives
+  uselistorder i32 %h, { 1, 0 }
+}
+
+declare void @use.1(i1)
+
+define internal i32 @test1_k(i8 %h, i32 %i) {
+; CHECK-LABEL: define {{.*}} @test1_k(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @e, align 4
+; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to %t1*
+; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test1_g(%t1* [[TMP1]], i32 0)
+; CHECK-NEXT:    [[FROMBOOL_1:%.*]] = zext i1 false to i8
+; CHECK-NEXT:    [[TOBOOL_1:%.*]] = trunc i8 [[FROMBOOL_1]] to i1
+; CHECK-NEXT:    call void @use.1(i1 [[TOBOOL_1]])
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %0 = load i32, i32* @e, align 4
+  %conv = sext i32 %0 to i64
+  %1 = inttoptr i64 %conv to %t1*
+  %call = call i1 @test1_g(%t1* %1, i32 %i)
+  %frombool.1 = zext i1 %call to i8
+  %tobool.1 = trunc i8 %frombool.1 to i1
+  call void @use.1(i1 %tobool.1)
+  ret i32 undef
+}
+
+define internal i1 @test1_g(%t1* %h, i32 %i) #0 {
+; CHECK-LABEL: define {{.*}} @test1_g(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test1_j()
+; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
+; CHECK-NEXT:    br label [[LAND_END]]
+; CHECK:       land.end:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
+; CHECK-NEXT:    ret i1 undef
+;
+entry:
+  %tobool = icmp ne i32 %i, 0
+  br i1 %tobool, label %land.rhs, label %land.end
+
+land.rhs:                                         ; preds = %entry
+  %call = call i32 (...) @test1_j()
+  %tobool1 = icmp ne i32 %call, 0
+  br label %land.end
+
+land.end:                                         ; preds = %land.rhs, %entry
+  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
+  ret i1 false
+}
+
+declare i32 @test1_j(...)
+
+define i32 @test2_m(i32 %h) #0 {
+; CHECK-LABEL: define {{.*}} @test2_m(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H:%.*]] to i8
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test2_k(i8 [[CONV]], i32 0)
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to %t1*
+; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test2_g(%t1* [[TMP0]], i32 1)
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %conv = trunc i32 %h to i8
+  %call = call i32 @test2_k(i8 %conv, i32 0)
+  %conv1 = sext i32 %h to i64
+  %0 = inttoptr i64 %conv1 to %t1*
+  %call2 = call i1 @test2_g(%t1* %0, i32 1)
+  ret i32 undef
+
+; uselistorder directives
+  uselistorder i32 %h, { 1, 0 }
+}
+
+; TODO: We could do better for the return value of call i1 @test3_g, if we
+;       resolve the unknown values there first.
+define internal i32 @test2_k(i8 %h, i32 %i) {
+; CHECK-LABEL: define {{.*}} @test2_k(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @e, align 4
+; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to %t1*
+; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(%t1* [[TMP1]], i32 0)
+; CHECK-NEXT:    [[FROMBOOL:%.*]] = icmp slt i1 false, true
+; CHECK-NEXT:    [[ADD:%.*]] = add i1 [[FROMBOOL]], [[FROMBOOL]]
+; CHECK-NEXT:    call void @use.1(i1 [[FROMBOOL]])
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %0 = load i32, i32* @e, align 4
+  %conv = sext i32 %0 to i64
+  %1 = inttoptr i64 %conv to %t1*
+  %call = call i1 @test3_g(%t1* %1, i32 %i)
+  %frombool = icmp slt i1 %call, 1
+  %add = add i1 %frombool, %frombool
+  call void @use.1(i1 %frombool)
+  ret i32 undef
+
+}
+
+define internal i1 @test2_g(%t1* %h, i32 %i) {
+; CHECK-LABEL: define {{.*}} @test2_g(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br i1 true, label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test2_j()
+; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
+; CHECK-NEXT:    br label [[LAND_END]]
+; CHECK:       land.end:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
+; CHECK-NEXT:    ret i1 undef
+;
+entry:
+  %tobool = icmp ne i32 %i, 0
+  br i1 %tobool, label %land.rhs, label %land.end
+
+land.rhs:                                         ; preds = %entry
+  %call = call i32 (...) @test2_j()
+  %tobool1 = icmp ne i32 %call, 0
+  br label %land.end
+
+land.end:                                         ; preds = %land.rhs, %entry
+  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
+  ret i1 false
+}
+
+declare i32 @test2_j(...)
+
+
+
+; Same as test_2*, but with a PHI node depending on a tracked  call result.
+define i32 @test3_m(i32 %h) #0 {
+; CHECK-LABEL: define {{.*}} @test3_m(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CONV:%.*]] = trunc i32 [[H:%.*]] to i8
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 @test3_k(i8 [[CONV]], i32 0)
+; CHECK-NEXT:    [[CONV1:%.*]] = sext i32 [[H]] to i64
+; CHECK-NEXT:    [[TMP0:%.*]] = inttoptr i64 [[CONV1]] to %t1*
+; CHECK-NEXT:    [[CALL2:%.*]] = call i1 @test3_g(%t1* [[TMP0]], i32 1)
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %conv = trunc i32 %h to i8
+  %call = call i32 @test3_k(i8 %conv, i32 0)
+  %conv1 = sext i32 %h to i64
+  %0 = inttoptr i64 %conv1 to %t1*
+  %call2 = call i1 @test3_g(%t1* %0, i32 1)
+  ret i32 undef
+
+; uselistorder directives
+  uselistorder i32 %h, { 1, 0 }
+}
+
+define internal i32 @test3_k(i8 %h, i32 %i) {
+; CHECK-LABEL: define {{.*}} @test3_k(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @e, align 4
+; CHECK-NEXT:    [[CONV:%.*]] = sext i32 [[TMP0]] to i64
+; CHECK-NEXT:    [[TMP1:%.*]] = inttoptr i64 [[CONV]] to %t1*
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[PHI:%.*]] = phi i1 [ undef, [[ENTRY:%.*]] ], [ false, [[LOOP]] ]
+; CHECK-NEXT:    [[CALL:%.*]] = call i1 @test3_g(%t1* [[TMP1]], i32 0)
+; CHECK-NEXT:    call void @use.1(i1 false)
+; CHECK-NEXT:    br i1 false, label [[LOOP]], label [[EXIT:%.*]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret i32 undef
+;
+entry:
+  %0 = load i32, i32* @e, align 4
+  %conv = sext i32 %0 to i64
+  %1 = inttoptr i64 %conv to %t1*
+  br label %loop
+
+loop:
+  %phi = phi i1 [ undef, %entry], [ %call, %loop ]
+  %call = call i1 @test3_g(%t1* %1, i32 %i)
+  %frombool = icmp slt i1 %call, 1
+  %add = add i1 %frombool, %frombool
+  call void @use.1(i1 %frombool)
+  br i1 %call, label %loop, label %exit
+
+exit:
+  ret i32 undef
+}
+
+define internal i1 @test3_g(%t1* %h, i32 %i) {
+; CHECK-LABEL: define {{.*}} @test3_g(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[I:%.*]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL]], label [[LAND_RHS:%.*]], label [[LAND_END:%.*]]
+; CHECK:       land.rhs:
+; CHECK-NEXT:    [[CALL:%.*]] = call i32 (...) @test3_j()
+; CHECK-NEXT:    [[TOBOOL1:%.*]] = icmp ne i32 [[CALL]], 0
+; CHECK-NEXT:    br label [[LAND_END]]
+; CHECK:       land.end:
+; CHECK-NEXT:    [[TMP0:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[TOBOOL1]], [[LAND_RHS]] ]
+; CHECK-NEXT:    ret i1 undef
+;
+entry:
+  %tobool = icmp ne i32 %i, 0
+  br i1 %tobool, label %land.rhs, label %land.end
+
+land.rhs:                                         ; preds = %entry
+  %call = call i32 (...) @test3_j()
+  %tobool1 = icmp ne i32 %call, 0
+  br label %land.end
+
+land.end:                                         ; preds = %land.rhs, %entry
+  %0 = phi i1 [ false, %entry ], [ %tobool1, %land.rhs ]
+  ret i1 false
+}
+
+declare i32 @test3_j(...)
+
+
+; TODO: We can eliminate the bitcast, if we resolve the unknown argument of
+;       @test4_b first.
+
+declare void @use.16(i16*)
+declare void @use.8(i8*)
+
+define void @test4_a() {
+; CHECK-LABEL: define {{.*}} @test4_a(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[TMP:%.*]] = call i8* @test4_c(i8* null)
+; CHECK-NEXT:    call void @test4_b(i8* null)
+; CHECK-NEXT:    ret void
+;
+bb:
+  %tmp = call i8* @test4_c(i8* null)
+  call void @test4_b(i8* %tmp)
+  ret void
+}
+
+define internal void @test4_b(i8* %arg) {
+; CHECK-LABEL: define {{.*}} @test4_b(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[TMP:%.*]] = bitcast i8* null to i16*
+; CHECK-NEXT:    call void @use.16(i16* [[TMP]])
+; CHECK-NEXT:    call void @use.8(i8* null)
+; CHECK-NEXT:    ret void
+;
+bb:
+  %tmp = bitcast i8* %arg to i16*
+  %sel = select i1 false, i8* %arg, i8* %arg
+  call void @use.16(i16* %tmp)
+  call void @use.8(i8* %sel)
+  ret void
+}
+
+define internal i8* @test4_c(i8* %arg) {
+; CHECK-LABEL: define {{.*}} @test4_c(
+; CHECK-NEXT:  bb1:
+; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
+; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    unreachable
+; CHECK:       bb3:
+; CHECK-NEXT:    ret i8* undef
+;
+bb1:                                              ; preds = %bb
+  %tmp = and i1 undef, undef
+  br i1 %tmp, label %bb3, label %bb2
+
+bb2:                                              ; preds = %bb1
+  unreachable
+
+bb3:                                              ; preds = %bb1
+  ret i8* null
+}
+
+; TODO: Same as test4, but with a select instead of a bitcast.
+
+define void @test5_a() {
+; CHECK-LABEL: define {{.*}} @test5_a(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[TMP:%.*]] = call i8* @test5_c(i8* null)
+; CHECK-NEXT:    call void @test5_b(i8* null)
+; CHECK-NEXT:    ret void
+;
+bb:
+  %tmp = call i8* @test5_c(i8* null)
+  call void @test5_b(i8* %tmp)
+  ret void
+}
+
+define internal void @test5_b(i8* %arg) {
+; CHECK-LABEL: define {{.*}} @test5_b(
+; CHECK-NEXT:  bb:
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 false, i8* null, i8* null
+; CHECK-NEXT:    call void @use.8(i8* [[SEL]])
+; CHECK-NEXT:    ret void
+;
+bb:
+  %sel = select i1 false, i8* %arg, i8* %arg
+  call void @use.8(i8* %sel)
+  ret void
+}
+
+define internal i8* @test5_c(i8* %arg) {
+; CHECK-LABEL: define {{.*}} @test5_c(
+; CHECK-NEXT:  bb1:
+; CHECK-NEXT:    [[TMP:%.*]] = and i1 undef, undef
+; CHECK-NEXT:    br i1 [[TMP]], label [[BB3:%.*]], label [[BB2:%.*]]
+; CHECK:       bb2:
+; CHECK-NEXT:    unreachable
+; CHECK:       bb3:
+; CHECK-NEXT:    ret i8* undef
+;
+bb1:                                              ; preds = %bb
+  %tmp = and i1 undef, undef
+  br i1 %tmp, label %bb3, label %bb2
+
+bb2:                                              ; preds = %bb1
+  unreachable
+
+bb3:                                              ; preds = %bb1
+  ret i8* null
+}
+
+
+
+ at contextsize = external dso_local local_unnamed_addr global i32, align 4
+ at pcount = internal local_unnamed_addr global i32 0, align 4
+ at maxposslen = external dso_local local_unnamed_addr global i32, align 4
+
+define void @test3() {
+; CHECK-LABEL: define {{.*}} @test3(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[IF_END16:%.*]]
+; CHECK:       if.end16:
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, i32* @contextsize, align 4
+; CHECK-NEXT:    [[SUB18:%.*]] = sub i32 undef, [[TMP0]]
+; CHECK-NEXT:    [[SUB19:%.*]] = sub i32 [[SUB18]], undef
+; CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32* @maxposslen, align 4
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], 8
+; CHECK-NEXT:    [[DIV:%.*]] = sdiv i32 undef, [[ADD]]
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32* @pcount, align 4
+; CHECK-NEXT:    [[MUL:%.*]] = mul nsw i32 [[DIV]], [[SUB19]]
+; CHECK-NEXT:    [[CMP20:%.*]] = icmp sgt i32 [[TMP2]], [[MUL]]
+; CHECK-NEXT:    br i1 [[CMP20]], label [[IF_THEN22:%.*]], label [[IF_END24:%.*]]
+; CHECK:       if.then22:
+; CHECK-NEXT:    store i32 [[MUL]], i32* @pcount, align 4
+; CHECK-NEXT:    ret void
+; CHECK:       if.end24:
+; CHECK-NEXT:    [[CMP25474:%.*]] = icmp sgt i32 [[TMP2]], 0
+; CHECK-NEXT:    br i1 [[CMP25474]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+; CHECK:       for.body:
+; CHECK-NEXT:    [[DIV30:%.*]] = sdiv i32 0, [[SUB19]]
+; CHECK-NEXT:    ret void
+; CHECK:       for.end:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %if.end16
+
+if.end16:                                         ; preds = %entry
+  %0 = load i32, i32* @contextsize, align 4
+  %sub18 = sub i32 undef, %0
+  %sub19 = sub i32 %sub18, undef
+  %1 = load i32, i32* @maxposslen, align 4
+  %add = add nsw i32 %1, 8
+  %div = sdiv i32 undef, %add
+  %2 = load i32, i32* @pcount, align 4
+  %mul = mul nsw i32 %div, %sub19
+  %cmp20 = icmp sgt i32 %2, %mul
+  br i1 %cmp20, label %if.then22, label %if.end24
+
+if.then22:                                        ; preds = %if.end16
+  store i32 %mul, i32* @pcount, align 4
+  ret void
+
+if.end24:                                         ; preds = %if.end16
+  %cmp25474 = icmp sgt i32 %2, 0
+  br i1 %cmp25474, label %for.body, label %for.end
+
+for.body:                                         ; preds = %if.end24
+  %3 = trunc i64 0 to i32
+  %div30 = sdiv i32 %3, %sub19
+  ret void
+
+for.end:                                          ; preds = %if.end24
+  ret void
+}

diff  --git a/llvm/test/Transforms/SCCP/switch-multiple-undef.ll b/llvm/test/Transforms/SCCP/switch-multiple-undef.ll
index 027c9c0c9ba7..df99e4eee7d2 100644
--- a/llvm/test/Transforms/SCCP/switch-multiple-undef.ll
+++ b/llvm/test/Transforms/SCCP/switch-multiple-undef.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -ipsccp < %s | FileCheck %s
 
 declare void @foo()
@@ -5,9 +6,25 @@ declare void @goo()
 declare void @patatino()
 
 define void @test1(i32 %t) {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[CHOICE:%.*]] = icmp eq i32 undef, -1
+; CHECK-NEXT:    switch i1 [[CHOICE]], label [[FIRST:%.*]] [
+; CHECK-NEXT:    i1 false, label [[SECOND:%.*]]
+; CHECK-NEXT:    i1 true, label [[THIRD:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       first:
+; CHECK-NEXT:    call void @foo()
+; CHECK-NEXT:    ret void
+; CHECK:       second:
+; CHECK-NEXT:    call void @goo()
+; CHECK-NEXT:    ret void
+; CHECK:       third:
+; CHECK-NEXT:    call void @patatino()
+; CHECK-NEXT:    ret void
+;
   %choice = icmp eq i32 undef, -1
   switch i1 %choice, label %first [i1 0, label %second
-                                   i1 1, label %third]
+  i1 1, label %third]
 first:
   call void @foo()
   ret void
@@ -18,10 +35,3 @@ third:
   call void @patatino()
   ret void
 }
-
-; CHECK: define void @test1(i32 %t) {
-; CHECK-NEXT:   br label %second
-; CHECK: second:
-; CHECK-NEXT:   call void @goo()
-; CHECK-NEXT:   ret void
-; CHECK-NEXT: }

diff  --git a/llvm/test/Transforms/SCCP/ub-shift.ll b/llvm/test/Transforms/SCCP/ub-shift.ll
index 3fb2d97457d9..6e15d6b2bccd 100644
--- a/llvm/test/Transforms/SCCP/ub-shift.ll
+++ b/llvm/test/Transforms/SCCP/ub-shift.ll
@@ -1,68 +1,89 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt < %s -sccp -S | FileCheck %s
 
-; CHECK-LABEL: shift_undef_64
 define void @shift_undef_64(i64* %p) {
+; CHECK-LABEL: @shift_undef_64(
+; CHECK-NEXT:    [[R1:%.*]] = lshr i64 -1, 4294967296
+; CHECK-NEXT:    store i64 [[R1]], i64* [[P:%.*]]
+; CHECK-NEXT:    [[R2:%.*]] = ashr i64 -1, 4294967297
+; CHECK-NEXT:    store i64 [[R2]], i64* [[P]]
+; CHECK-NEXT:    [[R3:%.*]] = shl i64 -1, 4294967298
+; CHECK-NEXT:    store i64 [[R3]], i64* [[P]]
+; CHECK-NEXT:    ret void
+;
   %r1 = lshr i64 -1, 4294967296 ; 2^32
-  ; CHECK: store i64 undef
   store i64 %r1, i64* %p
 
   %r2 = ashr i64 -1, 4294967297 ; 2^32 + 1
-  ; CHECK: store i64 undef
   store i64 %r2, i64* %p
 
   %r3 = shl i64 -1, 4294967298 ; 2^32 + 2
-  ; CHECK: store i64 undef
   store i64 %r3, i64* %p
 
   ret void
 }
 
-; CHECK-LABEL: shift_undef_65
 define void @shift_undef_65(i65* %p) {
+; CHECK-LABEL: @shift_undef_65(
+; CHECK-NEXT:    [[R1:%.*]] = lshr i65 2, -18446744073709551615
+; CHECK-NEXT:    store i65 [[R1]], i65* [[P:%.*]]
+; CHECK-NEXT:    [[R2:%.*]] = ashr i65 4, -18446744073709551615
+; CHECK-NEXT:    store i65 [[R2]], i65* [[P]]
+; CHECK-NEXT:    [[R3:%.*]] = shl i65 1, -18446744073709551615
+; CHECK-NEXT:    store i65 [[R3]], i65* [[P]]
+; CHECK-NEXT:    ret void
+;
   %r1 = lshr i65 2, 18446744073709551617
-  ; CHECK: store i65 undef
   store i65 %r1, i65* %p
 
   %r2 = ashr i65 4, 18446744073709551617
-  ; CHECK: store i65 undef
   store i65 %r2, i65* %p
 
   %r3 = shl i65 1, 18446744073709551617
-  ; CHECK: store i65 undef
   store i65 %r3, i65* %p
 
   ret void
 }
 
-; CHECK-LABEL: shift_undef_256
 define void @shift_undef_256(i256* %p) {
+; CHECK-LABEL: @shift_undef_256(
+; CHECK-NEXT:    [[R1:%.*]] = lshr i256 2, 18446744073709551617
+; CHECK-NEXT:    store i256 [[R1]], i256* [[P:%.*]]
+; CHECK-NEXT:    [[R2:%.*]] = ashr i256 4, 18446744073709551618
+; CHECK-NEXT:    store i256 [[R2]], i256* [[P]]
+; CHECK-NEXT:    [[R3:%.*]] = shl i256 1, 18446744073709551619
+; CHECK-NEXT:    store i256 [[R3]], i256* [[P]]
+; CHECK-NEXT:    ret void
+;
   %r1 = lshr i256 2, 18446744073709551617
-  ; CHECK: store i256 undef
   store i256 %r1, i256* %p
 
   %r2 = ashr i256 4, 18446744073709551618
-  ; CHECK: store i256 undef
   store i256 %r2, i256* %p
 
   %r3 = shl i256 1, 18446744073709551619
-  ; CHECK: store i256 undef
   store i256 %r3, i256* %p
 
   ret void
 }
 
-; CHECK-LABEL: shift_undef_511
 define void @shift_undef_511(i511* %p) {
+; CHECK-LABEL: @shift_undef_511(
+; CHECK-NEXT:    [[R1:%.*]] = lshr i511 -1, 1208925819614629174706276
+; CHECK-NEXT:    store i511 [[R1]], i511* [[P:%.*]]
+; CHECK-NEXT:    [[R2:%.*]] = ashr i511 -2, 1208925819614629174706200
+; CHECK-NEXT:    store i511 [[R2]], i511* [[P]]
+; CHECK-NEXT:    [[R3:%.*]] = shl i511 -3, 1208925819614629174706180
+; CHECK-NEXT:    store i511 [[R3]], i511* [[P]]
+; CHECK-NEXT:    ret void
+;
   %r1 = lshr i511 -1, 1208925819614629174706276 ; 2^80 + 100
-  ; CHECK: store i511 undef
   store i511 %r1, i511* %p
 
   %r2 = ashr i511 -2, 1208925819614629174706200
-  ; CHECK: store i511 undef
   store i511 %r2, i511* %p
 
   %r3 = shl i511 -3, 1208925819614629174706180
-  ; CHECK: store i511 undef
   store i511 %r3, i511* %p
 
   ret void

diff  --git a/llvm/test/Transforms/SCCP/undef-resolve.ll b/llvm/test/Transforms/SCCP/undef-resolve.ll
index 7fdcd556dae6..e2a4268596f4 100644
--- a/llvm/test/Transforms/SCCP/undef-resolve.ll
+++ b/llvm/test/Transforms/SCCP/undef-resolve.ll
@@ -1,12 +1,15 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -sccp -S < %s | FileCheck %s
 
 
 ; PR6940
 define double @test1() {
+; CHECK-LABEL: @test1(
+; CHECK-NEXT:    [[T:%.*]] = sitofp i32 undef to double
+; CHECK-NEXT:    ret double [[T]]
+;
   %t = sitofp i32 undef to double
   ret double %t
-; CHECK-LABEL: @test1(
-; CHECK: ret double 0.0
 }
 
 
@@ -14,6 +17,72 @@ define double @test1() {
 ; Check that lots of stuff doesn't get turned into undef.
 define i32 @test2() nounwind readnone ssp {
 ; CHECK-LABEL: @test2(
+; CHECK-NEXT:  init:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_OUTER:%.*]]
+; CHECK:       control.outer.loopexit.us-lcssa:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_LOOPEXIT:%.*]]
+; CHECK:       control.outer.loopexit:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_OUTER_BACKEDGE:%.*]]
+; CHECK:       control.outer.outer:
+; CHECK-NEXT:    [[SWITCHCOND_0_PH_PH:%.*]] = phi i32 [ 2, [[INIT:%.*]] ], [ 3, [[CONTROL_OUTER_OUTER_BACKEDGE]] ]
+; CHECK-NEXT:    [[I_0_PH_PH:%.*]] = phi i32 [ undef, [[INIT]] ], [ [[I_0_PH_PH_BE:%.*]], [[CONTROL_OUTER_OUTER_BACKEDGE]] ]
+; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq i32 [[I_0_PH_PH]], 0
+; CHECK-NEXT:    br i1 [[TMP4]], label [[CONTROL_OUTER_OUTER_SPLIT_US:%.*]], label [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE:%.*]]
+; CHECK:       control.outer.outer.control.outer.outer.split_crit_edge:
+; CHECK-NEXT:    br label [[CONTROL_OUTER:%.*]]
+; CHECK:       control.outer.outer.split.us:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_US:%.*]]
+; CHECK:       control.outer.us:
+; CHECK-NEXT:    [[A_0_PH_US:%.*]] = phi i32 [ [[SWITCHCOND_0_US:%.*]], [[BB3_US:%.*]] ], [ 4, [[CONTROL_OUTER_OUTER_SPLIT_US]] ]
+; CHECK-NEXT:    [[SWITCHCOND_0_PH_US:%.*]] = phi i32 [ [[A_0_PH_US]], [[BB3_US]] ], [ [[SWITCHCOND_0_PH_PH]], [[CONTROL_OUTER_OUTER_SPLIT_US]] ]
+; CHECK-NEXT:    br label [[CONTROL_US:%.*]]
+; CHECK:       bb3.us:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_US]]
+; CHECK:       bb0.us:
+; CHECK-NEXT:    br label [[CONTROL_US]]
+; CHECK:       control.us:
+; CHECK-NEXT:    [[SWITCHCOND_0_US]] = phi i32 [ [[A_0_PH_US]], [[BB0_US:%.*]] ], [ [[SWITCHCOND_0_PH_US]], [[CONTROL_OUTER_US]] ]
+; CHECK-NEXT:    switch i32 [[SWITCHCOND_0_US]], label [[CONTROL_OUTER_LOOPEXIT_US_LCSSA_US:%.*]] [
+; CHECK-NEXT:    i32 0, label [[BB0_US]]
+; CHECK-NEXT:    i32 1, label [[BB1_US_LCSSA_US:%.*]]
+; CHECK-NEXT:    i32 3, label [[BB3_US]]
+; CHECK-NEXT:    i32 4, label [[BB4_US_LCSSA_US:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       control.outer.loopexit.us-lcssa.us:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_LOOPEXIT]]
+; CHECK:       bb1.us-lcssa.us:
+; CHECK-NEXT:    br label [[BB1:%.*]]
+; CHECK:       bb4.us-lcssa.us:
+; CHECK-NEXT:    br label [[BB4:%.*]]
+; CHECK:       control.outer:
+; CHECK-NEXT:    [[A_0_PH:%.*]] = phi i32 [ [[NEXTID17:%.*]], [[BB3:%.*]] ], [ 4, [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE]] ]
+; CHECK-NEXT:    [[SWITCHCOND_0_PH:%.*]] = phi i32 [ 0, [[BB3]] ], [ [[SWITCHCOND_0_PH_PH]], [[CONTROL_OUTER_OUTER_CONTROL_OUTER_OUTER_SPLIT_CRIT_EDGE]] ]
+; CHECK-NEXT:    br label [[CONTROL:%.*]]
+; CHECK:       control:
+; CHECK-NEXT:    [[SWITCHCOND_0:%.*]] = phi i32 [ [[A_0_PH]], [[BB0:%.*]] ], [ [[SWITCHCOND_0_PH]], [[CONTROL_OUTER]] ]
+; CHECK-NEXT:    switch i32 [[SWITCHCOND_0]], label [[CONTROL_OUTER_LOOPEXIT_US_LCSSA:%.*]] [
+; CHECK-NEXT:    i32 0, label [[BB0]]
+; CHECK-NEXT:    i32 1, label [[BB1_US_LCSSA:%.*]]
+; CHECK-NEXT:    i32 3, label [[BB3]]
+; CHECK-NEXT:    i32 4, label [[BB4_US_LCSSA:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       bb4.us-lcssa:
+; CHECK-NEXT:    br label [[BB4]]
+; CHECK:       bb4:
+; CHECK-NEXT:    br label [[CONTROL_OUTER_OUTER_BACKEDGE]]
+; CHECK:       control.outer.outer.backedge:
+; CHECK-NEXT:    [[I_0_PH_PH_BE]] = phi i32 [ 1, [[BB4]] ], [ 0, [[CONTROL_OUTER_LOOPEXIT]] ]
+; CHECK-NEXT:    br label [[CONTROL_OUTER_OUTER]]
+; CHECK:       bb3:
+; CHECK-NEXT:    [[NEXTID17]] = add i32 [[SWITCHCOND_0]], -2
+; CHECK-NEXT:    br label [[CONTROL_OUTER]]
+; CHECK:       bb0:
+; CHECK-NEXT:    br label [[CONTROL]]
+; CHECK:       bb1.us-lcssa:
+; CHECK-NEXT:    br label [[BB1]]
+; CHECK:       bb1:
+; CHECK-NEXT:    ret i32 0
+;
 init:
   br label %control.outer.outer
 
@@ -46,16 +115,13 @@ bb3.us:                                           ; preds = %control.us
 bb0.us:                                           ; preds = %control.us
   br label %control.us
 
-; CHECK: control.us:                                       ; preds = %bb0.us, %control.outer.us
-; CHECK-NEXT:  %switchCond.0.us = phi i32
-; CHECK-NEXT:  switch i32 %switchCond.0.us
 control.us:                                       ; preds = %bb0.us, %control.outer.us
   %switchCond.0.us = phi i32 [ %A.0.ph.us, %bb0.us ], [ %switchCond.0.ph.us, %control.outer.us ] ; <i32> [#uses=2]
   switch i32 %switchCond.0.us, label %control.outer.loopexit.us-lcssa.us [
-    i32 0, label %bb0.us
-    i32 1, label %bb1.us-lcssa.us
-    i32 3, label %bb3.us
-    i32 4, label %bb4.us-lcssa.us
+  i32 0, label %bb0.us
+  i32 1, label %bb1.us-lcssa.us
+  i32 3, label %bb3.us
+  i32 4, label %bb4.us-lcssa.us
   ]
 
 control.outer.loopexit.us-lcssa.us:               ; preds = %control.us
@@ -75,10 +141,10 @@ control.outer:                                    ; preds = %bb3, %control.outer
 control:                                          ; preds = %bb0, %control.outer
   %switchCond.0 = phi i32 [ %A.0.ph, %bb0 ], [ %switchCond.0.ph, %control.outer ] ; <i32> [#uses=2]
   switch i32 %switchCond.0, label %control.outer.loopexit.us-lcssa [
-    i32 0, label %bb0
-    i32 1, label %bb1.us-lcssa
-    i32 3, label %bb3
-    i32 4, label %bb4.us-lcssa
+  i32 0, label %bb0
+  i32 1, label %bb1.us-lcssa
+  i32 3, label %bb3
+  i32 4, label %bb4.us-lcssa
   ]
 
 bb4.us-lcssa:                                     ; preds = %control
@@ -108,83 +174,105 @@ bb1:                                              ; preds = %bb1.us-lcssa, %bb1.
 ; Make sure SCCP honors the xor "idiom"
 ; rdar://9956541
 define i32 @test3() {
+; CHECK-LABEL: @test3(
+; CHECK-NEXT:    [[T:%.*]] = xor i32 undef, undef
+; CHECK-NEXT:    ret i32 [[T]]
+;
   %t = xor i32 undef, undef
   ret i32 %t
-; CHECK-LABEL: @test3(
-; CHECK: ret i32 0
 }
 
 ; Be conservative with FP ops
 define double @test4(double %x) {
+; CHECK-LABEL: @test4(
+; CHECK-NEXT:    [[T:%.*]] = fadd double [[X:%.*]], undef
+; CHECK-NEXT:    ret double [[T]]
+;
   %t = fadd double %x, undef
   ret double %t
-; CHECK-LABEL: @test4(
-; CHECK: fadd double %x, undef
 }
 
 ; Make sure casts produce a possible value
 define i32 @test5() {
+; CHECK-LABEL: @test5(
+; CHECK-NEXT:    [[T:%.*]] = sext i8 undef to i32
+; CHECK-NEXT:    ret i32 [[T]]
+;
   %t = sext i8 undef to i32
   ret i32 %t
-; CHECK-LABEL: @test5(
-; CHECK: ret i32 0
 }
 
 ; Make sure ashr produces a possible value
 define i32 @test6() {
+; CHECK-LABEL: @test6(
+; CHECK-NEXT:    [[T:%.*]] = ashr i32 undef, 31
+; CHECK-NEXT:    ret i32 [[T]]
+;
   %t = ashr i32 undef, 31
   ret i32 %t
-; CHECK-LABEL: @test6(
-; CHECK: ret i32 0
 }
 
 ; Make sure lshr produces a possible value
 define i32 @test7() {
+; CHECK-LABEL: @test7(
+; CHECK-NEXT:    [[T:%.*]] = lshr i32 undef, 31
+; CHECK-NEXT:    ret i32 [[T]]
+;
   %t = lshr i32 undef, 31
   ret i32 %t
-; CHECK-LABEL: @test7(
-; CHECK: ret i32 0
 }
 
 ; icmp eq with undef simplifies to undef
 define i1 @test8() {
+; CHECK-LABEL: @test8(
+; CHECK-NEXT:    [[T:%.*]] = icmp eq i32 undef, -1
+; CHECK-NEXT:    ret i1 [[T]]
+;
   %t = icmp eq i32 undef, -1
   ret i1 %t
-; CHECK-LABEL: @test8(
-; CHECK: ret i1 undef
 }
 
 ; Make sure we don't conclude that relational comparisons simplify to undef
 define i1 @test9() {
+; CHECK-LABEL: @test9(
+; CHECK-NEXT:    [[T:%.*]] = icmp ugt i32 undef, -1
+; CHECK-NEXT:    ret i1 [[T]]
+;
   %t = icmp ugt i32 undef, -1
   ret i1 %t
-; CHECK-LABEL: @test9(
-; CHECK: icmp ugt
 }
 
 ; Make sure we handle extractvalue
-define i64 @test10() { 
+define i64 @test10() {
+; CHECK-LABEL: @test10(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[E:%.*]] = extractvalue { i64, i64 } undef, 1
+; CHECK-NEXT:    ret i64 [[E]]
+;
 entry:
   %e = extractvalue { i64, i64 } undef, 1
   ret i64 %e
-; CHECK-LABEL: @test10(
-; CHECK: ret i64 undef
 }
 
 @GV = external global i32
 
 define i32 @test11(i1 %tobool) {
+; CHECK-LABEL: @test11(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[SHR4:%.*]] = ashr i32 undef, zext (i1 icmp eq (i32* bitcast (i32 (i1)* @test11 to i32*), i32* @GV) to i32)
+; CHECK-NEXT:    ret i32 [[SHR4]]
+;
 entry:
   %shr4 = ashr i32 undef, zext (i1 icmp eq (i32* bitcast (i32 (i1)* @test11 to i32*), i32* @GV) to i32)
   ret i32 %shr4
-; CHECK-LABEL: @test11(
-; CHECK: ret i32 0
 }
 
 ; Test unary ops
 define double @test12(double %x) {
+; CHECK-LABEL: @test12(
+; CHECK-NEXT:    [[T:%.*]] = fneg double undef
+; CHECK-NEXT:    ret double [[T]]
+;
   %t = fneg double undef
   ret double %t
-; CHECK-LABEL: @test12(
-; CHECK: double undef
 }


        


More information about the llvm-commits mailing list