Make APFloat->int conversions deterministic even in
cases with undefined behavior.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@42328 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Support/APFloat.cpp b/lib/Support/APFloat.cpp
index b3705f5..348b8ab 100644
--- a/lib/Support/APFloat.cpp
+++ b/lib/Support/APFloat.cpp
@@ -1399,13 +1399,28 @@
   unsigned int msb, partsCount;
   int bits;
 
-  /* Handle the three special cases first.  */
-  if(category == fcInfinity || category == fcNaN)
-    return opInvalidOp;
-
   partsCount = partCountForBits(width);
 
-  if(category == fcZero) {
+  /* Handle the three special cases first.  We produce
+     a deterministic result even for the Invalid cases. */
+  if (category == fcNaN) {
+    // Neither sign nor isSigned affects this.
+    APInt::tcSet(parts, 0, partsCount);
+    return opInvalidOp;
+  }
+  if (category == fcInfinity) {
+    if (!sign && isSigned)
+      APInt::tcSetLeastSignificantBits(parts, partsCount, width-1);
+    else if (!sign && !isSigned)
+      APInt::tcSetLeastSignificantBits(parts, partsCount, width);
+    else if (sign && isSigned) {
+      APInt::tcSetLeastSignificantBits(parts, partsCount, 1);
+      APInt::tcShiftLeft(parts, partsCount, width-1);
+    } else // sign && !isSigned
+      APInt::tcSet(parts, 0, partsCount);
+    return opInvalidOp;
+  }
+  if (category == fcZero) {
     APInt::tcSet(parts, 0, partsCount);
     return opOK;
   }
@@ -1418,6 +1433,19 @@
   if(bits > 0) {
     lost_fraction = tmp.shiftSignificandRight(bits);
   } else {
+    if (-bits >= semantics->precision) {
+      // Unrepresentably large.
+      if (!sign && isSigned)
+        APInt::tcSetLeastSignificantBits(parts, partsCount, width-1);
+      else if (!sign && !isSigned)
+        APInt::tcSetLeastSignificantBits(parts, partsCount, width);
+      else if (sign && isSigned) {
+        APInt::tcSetLeastSignificantBits(parts, partsCount, 1);
+        APInt::tcShiftLeft(parts, partsCount, width-1);
+      } else // sign && !isSigned
+        APInt::tcSet(parts, 0, partsCount);
+      return (opStatus)(opOverflow | opInexact);
+    }
     tmp.shiftSignificandLeft(-bits);
     lost_fraction = lfExactlyZero;
   }