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

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 12 10:03:08 PST 2020


Author: Florian Hahn
Date: 2020-02-12T18:02:18Z
New Revision: bb310b3f73dde5551bc2a0d564e88f7c831dfdb3

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

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

This version includes a fix for a set of crashes caused by marking
values depending on a yet unknown & tracked call as overdefined.

In some cases, we would later discover that the call has a constant
result and try to mark a user of it as constant, although it was already
marked as overdefined. Most instruction handlers bail out early if the
instruction is already overdefined. But that is not necessary for
CastInsts for example. By skipping values that depend on skipped
calls, we resolve the crashes and also improve the precision in some
cases (see resolvedundefsin-tracked-fn.ll).

Note that we may not skip PHI nodes that may depend on a skipped call,
but they can be safely marked as overdefined, as we bail out early if
the PHI node is overdefined.

This reverts the revert commit
a74b31a3e9cd844c7ce2087978568e3f5ec8519.

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..f110a1481d75 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.
@@ -996,8 +963,6 @@ void SCCPSolver::visitUnaryOperator(Instruction &I) {
   LatticeVal V0State = getValueState(I.getOperand(0));
 
   LatticeVal &IV = ValueState[&I];
-  if (IV.isOverdefined()) return;
-
   if (V0State.isConstant()) {
     Constant *C = ConstantExpr::get(I.getOpcode(), V0State.getConstant());
 
@@ -1032,8 +997,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 +1021,6 @@ void SCCPSolver::visitBinaryOperator(Instruction &I) {
       NonOverdefVal = &V1State;
     else if (!V2State.isOverdefined())
       NonOverdefVal = &V2State;
-
     if (NonOverdefVal) {
       if (NonOverdefVal->isUnknown())
         return;
@@ -1174,7 +1140,6 @@ void SCCPSolver::visitLoadInst(LoadInst &I) {
   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,11 +1414,11 @@ 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) {
+  // Keep track of values that dependent on an yet unknown tracked function call. It only makes sense to resolve them once the call is resolved.
+  SmallPtrSet<Value *, 8> DependsOnSkipped;
   for (BasicBlock &BB : F) {
     if (!BBExecutable.count(&BB))
       continue;
@@ -1468,14 +1433,15 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) {
         // Tracked calls must never be marked overdefined in ResolvedUndefsIn.
         if (CallSite CS = CallSite(&I))
           if (Function *F = CS.getCalledFunction())
-            if (MRVFunctionsTracked.count(F))
+            if (MRVFunctionsTracked.count(F)) {
+              DependsOnSkipped.insert(&I);
               continue;
+            }
 
         // extractvalue and insertvalue don't need to be marked; they are
         // 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 +1461,22 @@ 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))
+          if (TrackedRetVals.count(F)) {
+            DependsOnSkipped.insert(&I);
             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))
+      // Skip instructions that depend on results of calls we skipped earlier. Otherwise we might mark I as overdefined to early when we would end up discovering a constant value for I, if the call later resolves to a constant.
+      if (any_of(I.operands(), [&DependsOnSkipped](Value *V) {
+                 return DependsOnSkipped.find(V) != DependsOnSkipped.end(); })) {
+        DependsOnSkipped.insert(&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..bfc465f9281e
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/resolvedundefsin-tracked-fn.ll
@@ -0,0 +1,306 @@
+; 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:    call void @use.1(i1 false)
+; 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 }
+}
+
+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:    call void @use.1(i1 false)
+; 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(...)
+
+
+
+ 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