diff --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -580,8 +580,8 @@
 
 * ``%<fmtspec>`` is an optional scanf-style matching format specifier to
   indicate what number format to match (e.g. hex number).  Currently accepted
-  format specifier are ``%u``, ``%x`` and ``%X``.  If absent, the format
-  specifier defaults to ``%u``.
+  format specifier are ``%u``, ``%d``, ``%x`` and ``%X``.  If absent, the
+  format specifier defaults to ``%u``.
 
 * ``NUMVAR`` is the name of the numeric variable to define to the matching
   value.
diff --git a/llvm/include/llvm/Support/FileCheck.h b/llvm/include/llvm/Support/FileCheck.h
--- a/llvm/include/llvm/Support/FileCheck.h
+++ b/llvm/include/llvm/Support/FileCheck.h
@@ -40,10 +40,14 @@
 // Numeric expression handling code.
 //===----------------------------------------------------------------------===//
 
+class FileCheckNumExprVal;
+
 /// Bitfield representing the format a numeric expression value should be
 /// printed into for matching. Used to represent both explicit format
 /// specifiers as well as implicit format from using numeric variables.
 struct FileCheckNumExprFmt {
+  /// Value is a signed integer.
+  unsigned Signed : 1;
   /// Value should be printed as hex number.
   unsigned Hex : 1;
   /// Value should be printed using upper case letters, only used for hex
@@ -70,22 +74,98 @@
 
   /// Return the string representation of \p Value in the format represented by
   /// this instance.
-  std::string getMatchingString(uint64_t Value) const;
+  llvm::Optional<std::string>
+  getMatchingString(FileCheckNumExprVal &Value) const;
 
   /// Return the value corresponding to string representation \p StrVal
-  /// according to the matching format represented by this instance or nothing
-  /// if \p StrVal does not correspond to a valid and representable value.
-  llvm::Optional<uint64_t> valueFromStringRepr(StringRef StrVal) const;
+  /// according to the matching format represented by this instance or an
+  /// invalid value if \p StrVal does not correspond to a valid and
+  /// representable value.
+  FileCheckNumExprVal valueFromStringRepr(StringRef StrVal) const;
 };
 
 /// Initializer for numeric expression without format.
-const FileCheckNumExprFmt FmtNone = {0, 0, 0, 0};
+const FileCheckNumExprFmt FmtNone = {0, 0, 0, 0, 0};
 /// Initializer for numeric expression matched as unsigned value.
-const FileCheckNumExprFmt FmtUnsigned = {0, 0, 1, 0};
+const FileCheckNumExprFmt FmtUnsigned = {0, 0, 0, 1, 0};
+/// Initializer for numeric expression matched as signed value.
+const FileCheckNumExprFmt FmtSigned = {1, 0, 0, 1, 0};
 /// Initializer for numeric expression matched as lower case hex value.
-const FileCheckNumExprFmt FmtLowHex = {1, 0, 1, 0};
+const FileCheckNumExprFmt FmtLowHex = {0, 1, 0, 1, 0};
 /// Initializer for numeric expression matched as capital case hex value.
-const FileCheckNumExprFmt FmtCapHex = {1, 1, 1, 0};
+const FileCheckNumExprFmt FmtCapHex = {0, 1, 1, 1, 0};
+
+/// Class representing a numeric value.
+class FileCheckNumExprVal {
+private:
+  union {
+    int64_t SignedValue;
+    uint64_t UnsignedValue;
+  };
+
+  /// Whether value is signed (and thus is stored in SignedValue) or not (in
+  /// which case it is stored in UnsignedValue).
+  bool Signed;
+
+  /// Whether this holds an actual value. Examples of where this would be
+  /// false:
+  /// - underflow or overflow of one of the binary operation in the expression;
+  /// - unset variable's value.
+  bool Valid;
+
+public:
+  /// Constructor for an invalid value.
+  FileCheckNumExprVal() : Valid(false) {}
+
+  /// Constructor for a signed value.
+  explicit FileCheckNumExprVal(int64_t Val)
+      : SignedValue(Val), Signed(true), Valid(true) {}
+
+  /// Constructor for an unsigned value.
+  explicit FileCheckNumExprVal(uint64_t Val)
+      : UnsignedValue(Val), Signed(false), Valid(true) {}
+
+  /// Define equality to be true only if both values are valid and they have
+  /// the same signedness and corresponding value.  Tentative bit is ignored to
+  /// allow the evaluation of a numeric expression using variables with
+  /// tentative value to compare equal to a matched value.
+  bool operator==(const FileCheckNumExprVal &other);
+  bool operator!=(const FileCheckNumExprVal &other) {
+    return !(*this == other);
+  }
+
+  bool isSigned() const { return Signed; }
+
+  bool isValid() const { return Valid; }
+
+  /// Return the signed value. Must only be called if value is signed in the
+  /// first place.
+  int64_t getSignedValue() const {
+    assert(Signed);
+    return SignedValue;
+  }
+
+  /// Return the unsigned value. Must only be called if value is unsigned in
+  /// the first place.
+  uint64_t getUnsignedValue() const {
+    assert(!Signed);
+    return UnsignedValue;
+  }
+
+  /// Convert value to a signed value, or mark value invalid if not possible
+  /// (original value was not within range for a signed integer).
+  void convertSigned();
+
+  /// Convert value to an unsigned value, or mark value invalid if not possible
+  /// (original value was not within range for an unsigned integer).
+  void convertUnsigned();
+
+  /// Return an invalid value in case of underflow or overflow.
+  friend FileCheckNumExprVal operator+(const FileCheckNumExprVal &lhs,
+                                       const FileCheckNumExprVal &rhs);
+  friend FileCheckNumExprVal operator-(const FileCheckNumExprVal &lhs,
+                                       const FileCheckNumExprVal &rhs);
+};
 
 /// Base class representing the AST of a given numeric expression.
 class FileCheckNumExprAST {
@@ -94,7 +174,7 @@
 
   /// Evaluates and \returns the value of the expression represented by this
   /// AST.
-  virtual llvm::Optional<uint64_t> eval() const = 0;
+  virtual FileCheckNumExprVal eval() const = 0;
 
   /// \returns implicit format of this AST, FmtConflict if implicit formats of
   /// the AST's components conflict and Fmt none if the AST has no implicit
@@ -112,15 +192,18 @@
 class FileCheckNumExprLiteral : public FileCheckNumExprAST {
 private:
   /// Actual value of the literal.
-  uint64_t Value;
+  FileCheckNumExprVal Value;
 
 public:
+  /// Constructor for a signed literal.
+  FileCheckNumExprLiteral(int64_t Val) : Value(Val) {}
+
   /// Constructor for an unsigned literal.
   FileCheckNumExprLiteral(uint64_t Val) : Value(Val) {}
 
   /// Evaluates and returns the value of the expression represented by this
   /// AST. Therefore, \returns the literal's value.
-  llvm::Optional<uint64_t> eval() const { return Value; }
+  FileCheckNumExprVal eval() const { return Value; }
 
   /// Return implicit format of this AST, therefore FmtNone.
   FileCheckNumExprFmt getImplicitFmt() const { return FmtNone; }
@@ -169,8 +252,8 @@
   /// NumExpr points to a FileCheckNumExpr with a null AST.
   FileCheckNumExpr *NumExpr;
 
-  /// Value of numeric variable, if defined, or None otherwise.
-  llvm::Optional<uint64_t> Value;
+  /// Value of numeric variable.
+  FileCheckNumExprVal Value;
 
   /// Line number where this variable is defined. Used to determine whether a
   /// variable is defined on the same line as a given use.
@@ -181,12 +264,13 @@
   /// the numeric expression represented by NumExpr.
   FileCheckNumericVariable(StringRef Name, FileCheckNumExpr *NumExpr,
                            unsigned DefLineNumber)
-      : Name(Name), NumExpr(NumExpr), Value(llvm::None),
-        DefLineNumber(DefLineNumber) {}
+      : Name(Name), NumExpr(NumExpr), DefLineNumber(DefLineNumber) {
+    Value = FileCheckNumExprVal();
+  }
 
   /// Constructor for numeric variable \p Name with a known \p Value at parse
   /// time (e.g. the @LINE numeric variable).
-  explicit FileCheckNumericVariable(StringRef Name, uint64_t Value)
+  FileCheckNumericVariable(StringRef Name, FileCheckNumExprVal &Value)
       : Name(Name), NumExpr(nullptr), Value(Value) {}
 
   /// \returns name of that numeric variable.
@@ -198,7 +282,7 @@
   /// Evaluates and returns the value of the expression represented by this
   /// AST. Therefore, \returns this variable's value or the value of its
   /// associated numeric expression, if any.
-  llvm::Optional<uint64_t> eval() const;
+  FileCheckNumExprVal eval() const;
 
   /// \returns whether this variable's value is known at match time, when
   /// performing the substitutions.
@@ -212,7 +296,7 @@
 
   /// Sets value of this numeric variable if not defined. \returns whether the
   /// variable was already defined.
-  bool setValue(uint64_t Value);
+  bool setValue(FileCheckNumExprVal Value);
 
   /// Clears value of this numeric variable. \returns whether the variable was
   /// already undefined.
@@ -223,7 +307,8 @@
 };
 
 /// Type of functions evaluating a given binary operation.
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
+using binop_eval_t = FileCheckNumExprVal (*)(const FileCheckNumExprVal &,
+                                             const FileCheckNumExprVal &);
 
 /// Class representing a single binary operation in the AST of a numeric
 /// expression.
@@ -244,11 +329,10 @@
                     std::shared_ptr<FileCheckNumExprAST> OperandRight)
       : LeftOp(OperandLeft), RightOp(OperandRight), EvalBinop(EvalBinop) {}
 
-  /// Evaluates the value of the binary operation represented by this AST,
-  /// using EvalBinop on the result of recursively evaluating the operands.
-  /// \returns None if any numeric variable used is undefined, or the
-  /// expression value otherwise.
-  llvm::Optional<uint64_t> eval() const;
+  /// Evaluates and \returns the value of the binary operation represented by
+  /// this AST. Uses EvalBinop to perform the binary operation on the values of
+  /// recursively evaluating the left and right operands.
+  FileCheckNumExprVal eval() const;
 
   /// \returns implicit format of this AST, FmtConflict if implicit formats of
   /// the AST's components conflict and Fmt none if the AST has no implicit
diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -25,7 +25,8 @@
 using namespace llvm;
 
 bool FileCheckNumExprFmt::operator==(const FileCheckNumExprFmt &other) {
-  return Valid == other.Valid && Hex == other.Hex && Cap == other.Cap;
+  return Valid == other.Valid && Conflict == other.Conflict &&
+         Signed == other.Signed && Hex == other.Hex && Cap == other.Cap;
 }
 
 StringRef FileCheckNumExprFmt::getWildcardRegex() const {
@@ -35,27 +36,162 @@
       return StringRef("[[:digit:]A-F]+");
     else
       return StringRef("[[:digit:]a-f]+");
-  } else
+  } else if (Signed)
+    return StringRef("-?[[:digit:]]+");
+  else
     return StringRef("[[:digit:]]+");
 }
 
-std::string FileCheckNumExprFmt::getMatchingString(uint64_t Value) const {
-  assert(Valid && !Conflict && "Trying to match value with invalid format");
+llvm::Optional<std::string>
+FileCheckNumExprFmt::getMatchingString(FileCheckNumExprVal &Value) const {
+  if (Signed)
+    Value.convertSigned();
+  else
+    Value.convertUnsigned();
+
+  assert(!Conflict);
+  // Conversion error (e.g. negative value converted to unsigned).
+  if (!Valid)
+    return llvm::None;
+
   if (Hex)
-    return utohexstr(Value, !Cap);
+    return utohexstr(Value.getUnsignedValue(), !Cap);
+  else if (Signed)
+    return itostr(Value.getSignedValue());
   else
-    return utostr(Value);
+    return utostr(Value.getUnsignedValue());
 }
 
-llvm::Optional<uint64_t>
+FileCheckNumExprVal
 FileCheckNumExprFmt::valueFromStringRepr(StringRef StrVal) const {
   unsigned Radix = Hex ? 16 : 10;
-  uint64_t Value;
+  if (Signed) {
+    int64_t SignedValue;
 
-  if (StrVal.getAsInteger(Radix, Value))
-    return llvm::None;
+    if (StrVal.getAsInteger(Radix, SignedValue))
+      return FileCheckNumExprVal();
+
+    return FileCheckNumExprVal(SignedValue);
+  } else {
+    uint64_t UnsignedValue;
 
-  return Value;
+    if (StrVal.getAsInteger(Radix, UnsignedValue))
+      return FileCheckNumExprVal();
+
+    return FileCheckNumExprVal(UnsignedValue);
+  }
+}
+
+bool FileCheckNumExprVal::operator==(const FileCheckNumExprVal &other) {
+  if (!Valid || !other.Valid)
+    return false;
+
+  if (Signed)
+    return SignedValue == other.SignedValue;
+  else
+    return UnsignedValue == other.UnsignedValue;
+}
+
+void FileCheckNumExprVal::convertSigned() {
+  if (!Valid || Signed)
+    return;
+
+  if (UnsignedValue > std::numeric_limits<int64_t>::max()) {
+    Valid = false;
+    return;
+  }
+
+  SignedValue = UnsignedValue;
+  Signed = true;
+}
+
+void FileCheckNumExprVal::convertUnsigned() {
+  if (!Valid || !Signed)
+    return;
+
+  if (SignedValue < 0) {
+    Valid = false;
+    return;
+  }
+
+  UnsignedValue = SignedValue;
+  Signed = false;
+  return;
+}
+
+llvm::FileCheckNumExprVal llvm::
+operator+(const llvm::FileCheckNumExprVal &Op1,
+          const llvm::FileCheckNumExprVal &Op2) {
+  // Operands must be valid.
+  if (!Op1.Valid || !Op2.Valid)
+    return FileCheckNumExprVal();
+
+  // Operands must have same sign.
+  if (Op1.Signed != Op2.Signed)
+    return FileCheckNumExprVal();
+
+  if (Op1.Signed) {
+    int64_t Val1 = Op1.SignedValue;
+    int64_t Val2 = Op2.SignedValue;
+
+    // Op1 + Op2 > max int64_t.
+    if (Val1 > 0 && Val2 > 0 &&
+        Val1 > (std::numeric_limits<int64_t>::max() - Val2))
+      return FileCheckNumExprVal();
+
+    // Op1 + Op2 < min int64_t.
+    if (Val1 < 0 && Val2 < 0 &&
+        Val1 < (std::numeric_limits<int64_t>::min() - Val2))
+      return FileCheckNumExprVal();
+
+    return FileCheckNumExprVal(Val1 + Val2);
+  } else {
+    uint64_t Val1 = Op1.UnsignedValue;
+    uint64_t Val2 = Op2.UnsignedValue;
+
+    // Op1 + Op2 > max uint64_t.
+    if (Val1 > std::numeric_limits<uint64_t>::max() - Val2)
+      return FileCheckNumExprVal();
+
+    return FileCheckNumExprVal(Val1 + Val2);
+  }
+}
+
+llvm::FileCheckNumExprVal llvm::
+operator-(const llvm::FileCheckNumExprVal &Op1,
+          const llvm::FileCheckNumExprVal &Op2) {
+  // Operands must be valid.
+  if (!Op1.Valid || !Op2.Valid)
+    return FileCheckNumExprVal();
+
+  // Operands must have same sign.
+  if (Op1.Signed != Op2.Signed)
+    return FileCheckNumExprVal();
+
+  if (Op1.Signed) {
+    int64_t Val1 = Op1.SignedValue;
+    int64_t Val2 = Op2.SignedValue;
+
+    // Op1 - Op2 > max int64_t.
+    if (Val1 > 0 && Val2 < 0 &&
+        Val1 > (std::numeric_limits<int64_t>::max() + Val2))
+      return FileCheckNumExprVal();
+
+    // Op1 - Op2 < min int64_t.
+    if (Val1 < 0 && Val2 > 0 &&
+        Val1 < (std::numeric_limits<int64_t>::min() + Val2))
+      return FileCheckNumExprVal();
+
+    return FileCheckNumExprVal(Val1 - Val2);
+  } else {
+    uint64_t Val1 = Op1.UnsignedValue;
+    uint64_t Val2 = Op2.UnsignedValue;
+
+    // Op1 < Op2.
+    if (Val1 < Val2)
+      return FileCheckNumExprVal();
+    return FileCheckNumExprVal(Val1 - Val2);
+  }
 }
 
 FileCheckNumExpr::FileCheckNumExpr(std::shared_ptr<FileCheckNumExprAST> AST,
@@ -67,18 +203,18 @@
     this->Fmt = FmtUnsigned;
 }
 
-llvm::Optional<uint64_t> FileCheckNumericVariable::eval() const {
-  if (Value)
+FileCheckNumExprVal FileCheckNumericVariable::eval() const {
+  if (Value.isValid())
     return Value;
 
   if (NumExpr == nullptr || NumExpr->getAST() == nullptr)
-    return llvm::None;
+    return FileCheckNumExprVal();
 
   return NumExpr->getAST()->eval();
 }
 
 bool FileCheckNumericVariable::isMatchTimeKnown() const {
-  if (Value)
+  if (Value.isValid())
     return true;
 
   return NumExpr != nullptr && NumExpr->getAST() != nullptr;
@@ -93,34 +229,40 @@
 
 void FileCheckNumericVariable::appendUndefVarNames(
     std::vector<StringRef> &UndefVarNames) const {
-  if (!Value)
+  if (!Value.isValid())
     UndefVarNames.emplace_back(Name);
 }
 
-bool FileCheckNumericVariable::setValue(uint64_t NewValue) {
-  if (Value)
+bool FileCheckNumericVariable::setValue(FileCheckNumExprVal NewValue) {
+  if (Value.isValid())
     return true;
+  assert(NewValue.isValid() && "Setting invalid value");
   Value = NewValue;
   return false;
 }
 
 bool FileCheckNumericVariable::clearValue() {
-  if (!Value)
+  if (!Value.isValid())
     return true;
-  Value = llvm::None;
+  Value = FileCheckNumExprVal();
   NumExpr = nullptr;
   return false;
 }
 
-llvm::Optional<uint64_t> FileCheckASTBinop::eval() const {
-  llvm::Optional<uint64_t> LeftOp = this->LeftOp->eval();
-  llvm::Optional<uint64_t> RightOp = this->RightOp->eval();
+FileCheckNumExprVal FileCheckASTBinop::eval() const {
+  FileCheckNumExprVal LeftValue = LeftOp->eval();
+  FileCheckNumExprVal RightValue = RightOp->eval();
 
-  // Uses undefined variable.
-  if (!LeftOp || !RightOp)
-    return llvm::None;
+  // Integer promotion.
+  if (!LeftValue.isSigned() || !RightValue.isSigned()) {
+    LeftValue.convertUnsigned();
+    RightValue.convertUnsigned();
+  }
+
+  if (!LeftValue.isValid() || !RightValue.isValid())
+    return FileCheckNumExprVal();
 
-  return EvalBinop(*LeftOp, *RightOp);
+  return EvalBinop(LeftValue, RightValue);
 }
 
 FileCheckNumExprFmt FileCheckASTBinop::getImplicitFmt() const {
@@ -134,8 +276,6 @@
   return Fmt;
 }
 
-/// Append names of undefined variables used in any of the operands of this
-/// binary operation.
 void FileCheckASTBinop::appendUndefVarNames(
     std::vector<StringRef> &UndefVarNames) const {
   LeftOp->appendUndefVarNames(UndefVarNames);
@@ -146,11 +286,12 @@
   if (IsNumExpr) {
     assert(NumExpr->getAST() != nullptr &&
            "Substituting empty numeric expression");
-    llvm::Optional<uint64_t> EvaluatedValue = NumExpr->getAST()->eval();
-    if (!EvaluatedValue)
+    FileCheckNumExprVal EvaluatedValue = NumExpr->getAST()->eval();
+    if (!EvaluatedValue.isValid())
       return llvm::None;
+
     FileCheckNumExprFmt Fmt = NumExpr->getEffectiveFmt();
-    return Fmt.getMatchingString(*EvaluatedValue);
+    return Fmt.getMatchingString(EvaluatedValue);
   }
 
   // Look up the value and escape it so that we can put it into the regex.
@@ -309,18 +450,19 @@
   if (AO != LegacyLiteral && AO != Any)
     return nullptr;
   unsigned Radix = (AO == LegacyLiteral) ? 10 : 0;
-  uint64_t LiteralValue;
-  if (Expr.consumeInteger(Radix, LiteralValue))
-    return nullptr;
-  return std::make_shared<FileCheckNumExprLiteral>(LiteralValue);
-}
-
-static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
-  return LeftOp + RightOp;
-}
-
-static uint64_t sub(uint64_t LeftOp, uint64_t RightOp) {
-  return LeftOp - RightOp;
+  int64_t SignedLiteralValue;
+  uint64_t UnsignedLiteralValue;
+  StringRef SaveExpr = Expr;
+  // Accept both signed and unsigned literal.
+  if (AO != LegacyLiteral && !Expr.consumeInteger(Radix, SignedLiteralValue)) {
+    return std::make_shared<FileCheckNumExprLiteral>(SignedLiteralValue);
+  } else {
+    Expr = SaveExpr;
+    if (!Expr.consumeInteger(Radix, UnsignedLiteralValue)) {
+      return std::make_shared<FileCheckNumExprLiteral>(UnsignedLiteralValue);
+    } else
+      return nullptr;
+  }
 }
 
 std::shared_ptr<FileCheckNumExprAST> FileCheckPattern::parseFileCheckBinop(
@@ -337,10 +479,10 @@
   binop_eval_t EvalBinop;
   switch (Operator) {
   case '+':
-    EvalBinop = add;
+    EvalBinop = operator+;
     break;
   case '-':
-    EvalBinop = sub;
+    EvalBinop = operator-;
     break;
   default:
     SM.PrintMessage(OpLoc, SourceMgr::DK_Error,
@@ -394,6 +536,9 @@
     case 'u':
       ExplicitFmt = FmtUnsigned;
       break;
+    case 'd':
+      ExplicitFmt = FmtSigned;
+      break;
     case 'x':
       ExplicitFmt = FmtLowHex;
       break;
@@ -498,8 +643,9 @@
   // Create fake @LINE pseudo variable definition.
   StringRef LinePseudo = "@LINE";
   uint64_t LineNumber64 = LineNumber;
+  auto LineNumberVal = FileCheckNumExprVal(LineNumber64);
   std::shared_ptr<FileCheckNumericVariable> LinePseudoVar =
-      std::make_shared<FileCheckNumericVariable>(LinePseudo, LineNumber64);
+      std::make_shared<FileCheckNumericVariable>(LinePseudo, LineNumberVal);
   Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar;
 
   if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
@@ -811,8 +957,13 @@
     for (const auto &Substitution : Substitutions) {
       // Substitute and check for failure (e.g. use of undefined variable).
       llvm::Optional<std::string> Value = Substitution.getResult();
-      if (!Value)
+      if (!Value) {
+        SM.PrintMessage(
+            SMLoc::getFromPointer(Substitution.getFromString().data()),
+            SourceMgr::DK_Error,
+            "Unable to substitute variable or numeric expression");
         return StringRef::npos;
+      }
 
       // Plop it into the regex at the adjusted offset.
       TmpStr.insert(TmpStr.begin() + Substitution.getIndex() + InsertOffset,
@@ -851,12 +1002,12 @@
     assert(DefinedNumericVariable->getNumExpr() != nullptr);
     FileCheckNumExprFmt Fmt =
         DefinedNumericVariable->getNumExpr()->getEffectiveFmt();
-    llvm::Optional<uint64_t> Value = Fmt.valueFromStringRepr(MatchedValue);
-    if (!Value) {
+    FileCheckNumExprVal Value = Fmt.valueFromStringRepr(MatchedValue);
+    if (!Value.isValid()) {
       SM.PrintMessage(SMLoc::getFromPointer(MatchedValue.data()),
                       SourceMgr::DK_Error, "Unable to represent numeric value");
     }
-    if (DefinedNumericVariable->setValue(*Value))
+    if (DefinedNumericVariable->setValue(Value))
       assert(false && "Numeric variable redefined");
   }
 
@@ -1958,15 +2109,15 @@
         ErrorFound = true;
         continue;
       }
-      llvm::Optional<uint64_t> Value = NumExpr->getAST()->eval();
-      if (!Value) {
+      FileCheckNumExprVal Value = NumExpr->getAST()->eval();
+      if (!Value.isValid()) {
         SM.PrintMessage(SMLoc::getFromPointer(CmdlineDefExpr.data()),
                         SourceMgr::DK_Error,
                         "unable to represent numeric value");
         ErrorFound = true;
         continue;
       }
-      DefinedNumericVariable->setValue(*Value);
+      DefinedNumericVariable->setValue(Value);
 
       // Record this variable definition.
       GlobalNumericVariableTable[DefinedNumericVariable->getName()] =
diff --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt
--- a/llvm/test/FileCheck/numeric-expression.txt
+++ b/llvm/test/FileCheck/numeric-expression.txt
@@ -20,25 +20,27 @@
 
 ; Numeric variable definition with explicit matching format
 DEF FMT
+-30
 c
 D
 ; CHECK-LABEL: DEF FMT
-; CHECK-NEXT: [[#%x,VAR2:]]
-; CHECK-NEXT: [[#%X,VAR3:]]
+; CHECK-NEXT: [[#%d,VAR2:]]
+; CHECK-NEXT: [[#%x,VAR3:]]
+; CHECK-NEXT: [[#%X,VAR4:]]
 
 ; Numeric variable definition with explicit matching format in alternate spacing
 DEF FMT ALT SPC
-c
-c
-c
-c
-c
+-30
+-30
+-30
+-30
+-30
 ; CHECK-LABEL: DEF FMT ALT SPC
-; CHECK-NEXT: [[#%x, VAR2a:]]
-; CHECK-NEXT: [[# %x, VAR2b:]]
-; CHECK-NEXT: [[# %x , VAR2c:]]
-; CHECK-NEXT: [[# %x , VAR2d :]]
-; CHECK-NEXT: [[# %x , VAR2e : ]]
+; CHECK-NEXT: [[#%d, VAR2a:]]
+; CHECK-NEXT: [[# %d, VAR2b:]]
+; CHECK-NEXT: [[# %d , VAR2c:]]
+; CHECK-NEXT: [[# %d , VAR2d :]]
+; CHECK-NEXT: [[# %d , VAR2e : ]]
 
 ; Numeric expressions in explicit matching format and default matching rule using
 ; variables defined on other lines
@@ -46,26 +48,36 @@
 11
 12
 10
+-30
+-29
+-31
 c
 d
 b
 1a
+1a
 D
 E
 C
 1B
+1B
 ; CHECK-LABEL: USE DEF FMT IMPL MATCH
 ; CHECK-NEXT: [[#%u,VAR1]]
 ; CHECK-NEXT: [[#%u,VAR1+1]]
 ; CHECK-NEXT: [[#%u,VAR1-1]]
-; CHECK-NEXT: [[#%x,VAR2]]
-; CHECK-NEXT: [[#%x,VAR2+1]]
-; CHECK-NEXT: [[#%x,VAR2-1]]
-; CHECK-NEXT: [[#%x,VAR2+14]]
-; CHECK-NEXT: [[#%X,VAR3]]
-; CHECK-NEXT: [[#%X,VAR3+1]]
-; CHECK-NEXT: [[#%X,VAR3-1]]
-; CHECK-NEXT: [[#%X,VAR3+14]]
+; CHECK-NEXT: [[#%d,VAR2]]
+; CHECK-NEXT: [[#%d,VAR2+1]]
+; CHECK-NEXT: [[#%d,VAR2-1]]
+; CHECK-NEXT: [[#%x,VAR3]]
+; CHECK-NEXT: [[#%x,VAR3+1]]
+; CHECK-NEXT: [[#%x,VAR3-1]]
+; CHECK-NEXT: [[#%x,VAR3+0xe]]
+; CHECK-NEXT: [[#%x,VAR3+0xE]]
+; CHECK-NEXT: [[#%X,VAR4]]
+; CHECK-NEXT: [[#%X,VAR4+1]]
+; CHECK-NEXT: [[#%X,VAR4-1]]
+; CHECK-NEXT: [[#%X,VAR4+0xe]]
+; CHECK-NEXT: [[#%X,VAR4+0xE]]
 
 ; Numeric expressions in explicit matching format and default matching rule using
 ; variables defined on other lines in alternate spacing
@@ -108,14 +120,19 @@
 11
 12
 10
+-30
+-29
+-31
 c
 d
 b
 1a
+1a
 D
 E
 C
 1B
+1B
 ; CHECK-LABEL: USE IMPL FMT IMPL MATCH
 ; CHECK-NEXT: [[#VAR1]]
 ; CHECK-NEXT: [[#VAR1+1]]
@@ -123,17 +140,22 @@
 ; CHECK-NEXT: [[#VAR2]]
 ; CHECK-NEXT: [[#VAR2+1]]
 ; CHECK-NEXT: [[#VAR2-1]]
-; CHECK-NEXT: [[#VAR2+14]]
 ; CHECK-NEXT: [[#VAR3]]
 ; CHECK-NEXT: [[#VAR3+1]]
 ; CHECK-NEXT: [[#VAR3-1]]
-; CHECK-NEXT: [[#VAR3+14]]
+; CHECK-NEXT: [[#VAR3+0xe]]
+; CHECK-NEXT: [[#VAR3+0xE]]
+; CHECK-NEXT: [[#VAR4]]
+; CHECK-NEXT: [[#VAR4+1]]
+; CHECK-NEXT: [[#VAR4-1]]
+; CHECK-NEXT: [[#VAR4+0xe]]
+; CHECK-NEXT: [[#VAR4+0xE]]
 
 ; Explicit format override implicit format conflicts
 VAR USE IMPL OVERRIDE FMT CONFLICT
 23
 ; CHECK-LABEL: VAR USE IMPL OVERRIDE FMT CONFLICT
-; CHECK-NEXT: [[# %u, VAR1 + VAR2]]
+; CHECK-NEXT: [[# %u, VAR1 + VAR3]]
 
 ; Numeric expressions using variables defined on the command-line and an
 ; immediate interpreted as an unsigned value
@@ -149,12 +171,16 @@
 b
 B
 12
+12
+13
 13
 ; CHECK-LABEL: USE CONV FMT IMPL MATCH
 ; CHECK-NEXT: [[# %x, VAR1]]
 ; CHECK-NEXT: [[# %X, VAR1]]
-; CHECK-NEXT: [[# %u, VAR2]]
 ; CHECK-NEXT: [[# %u, VAR3]]
+; CHECK-NEXT: [[# %d, VAR3]]
+; CHECK-NEXT: [[# %u, VAR4]]
+; CHECK-NEXT: [[# %d, VAR4]]
 
 ; Numeric variable definition with unsupported matching format
 ; RUN: not FileCheck -check-prefixes ERR,INVALID-FMT-SPEC1 -input-file %s %s 2>&1 \
@@ -272,3 +298,29 @@
 ; FMT-CONFLICT-MSG: numeric-expression.txt:[[#@LINE-1]]:25: error: variables with conflicting format specifier: need an explicit one
 ; FMT-CONFLICT-MSG-NEXT: {{F}}MT-CONFLICT-NEXT: {{\[\[#VAR1 \+ VAR2\]\]}}
 ; FMT-CONFLICT-MSG-NEXT: {{^                        \^$}}
+
+
+; Numeric expression with overflow
+; RUN: not FileCheck -check-prefix OVERFLOW -input-file %s %s 2>&1 \
+; RUN:   | FileCheck -check-prefix OVERFLOW-MSG %s
+
+OVERFLOW
+BIGVAR=10000000000000000
+; OVERFLOW-LABEL: OVERFLOW
+; OVERFLOW-NEXT: BIGVAR: [[#BIGVAR:0x8000000000000000+0x8000000000000000]]
+; OVERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:29: error: Unable to substitute variable or numeric expression
+; OVERFLOW-MSG-NEXT: {{O}}VERFLOW-NEXT: BIGVAR: {{\[\[#BIGVAR:0x8000000000000000\+0x8000000000000000\]\]}}
+; OVERFLOW-MSG-NEXT: {{^                            \^$}}
+
+
+; Numeric expression with underflow
+; RUN: not FileCheck -check-prefix UNDERFLOW -input-file %s %s 2>&1 \
+; RUN:   | FileCheck -check-prefix UNDERFLOW-MSG %s
+
+UNDERFLOW
+TINYVAR=-10000000000000000
+; UNDERFLOW-LABEL: UNDERFLOW
+; UNDERFLOW-NEXT: TINYVAR: [[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000]]
+; UNDERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: Unable to substitute variable or numeric expression
+; UNDERFLOW-MSG-NEXT: {{U}}NDERFLOW-NEXT: TINYVAR: {{\[\[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000\]\]}}
+; UNDERFLOW-MSG-NEXT: {{^                              \^$}}
diff --git a/llvm/unittests/Support/FileCheckTest.cpp b/llvm/unittests/Support/FileCheckTest.cpp
--- a/llvm/unittests/Support/FileCheckTest.cpp
+++ b/llvm/unittests/Support/FileCheckTest.cpp
@@ -16,10 +16,10 @@
 
 TEST_F(FileCheckTest, Literal) {
   // Eval returns the literal's value.
-  auto Ten = FileCheckNumExprLiteral(10);
-  llvm::Optional<uint64_t> Value = Ten.eval();
-  EXPECT_TRUE(Value);
-  EXPECT_EQ((uint64_t)10, *Value);
+  auto Ten = FileCheckNumExprLiteral((uint64_t)10);
+  FileCheckNumExprVal Value = Ten.eval();
+  EXPECT_TRUE(Value.isValid());
+  EXPECT_EQ((uint64_t)10, Value.getUnsignedValue());
 
   // Literal has no undefined variable.
   std::vector<StringRef> UndefVarNames;
@@ -34,22 +34,24 @@
   auto NumVarExpr = FileCheckNumExpr(nullptr, FmtUnsigned);
   FileCheckNumericVariable FooVar =
       FileCheckNumericVariable("FOO", &NumVarExpr, 1U);
-  llvm::Optional<uint64_t> Value = FooVar.eval();
-  EXPECT_FALSE(Value);
+  FileCheckNumExprVal Value = FooVar.eval();
+  EXPECT_FALSE(Value.isValid());
   EXPECT_TRUE(FooVar.clearValue());
   std::vector<StringRef> UndefVarNames;
   EXPECT_TRUE(UndefVarNames.empty());
   FooVar.appendUndefVarNames(UndefVarNames);
   EXPECT_EQ(1U, UndefVarNames.size());
   EXPECT_EQ("FOO", UndefVarNames[0]);
-  EXPECT_FALSE(FooVar.setValue((uint64_t)42));
+  FileCheckNumExprVal LifeAnswer = FileCheckNumExprVal((uint64_t)42);
+  EXPECT_FALSE(FooVar.setValue(LifeAnswer));
 
   // Defined variable: eval returns value set, setValue fails and
   // appendUndefVarNames is a nop.
   Value = FooVar.eval();
-  EXPECT_TRUE(Value);
-  EXPECT_EQ((uint64_t)42, *Value);
-  EXPECT_TRUE(FooVar.setValue((uint64_t)43));
+  EXPECT_TRUE(Value.isValid());
+  EXPECT_EQ((uint64_t)42, Value.getUnsignedValue());
+  FileCheckNumExprVal FourThree = FileCheckNumExprVal((uint64_t)43);
+  EXPECT_TRUE(FooVar.setValue(FourThree));
   UndefVarNames.clear();
   EXPECT_TRUE(UndefVarNames.empty());
   FooVar.appendUndefVarNames(UndefVarNames);
@@ -59,7 +61,7 @@
   // appendUndefVarNames returns the variable again.
   EXPECT_FALSE(FooVar.clearValue());
   Value = FooVar.eval();
-  EXPECT_FALSE(Value);
+  EXPECT_FALSE(Value.isValid());
   EXPECT_TRUE(FooVar.clearValue());
   EXPECT_TRUE(UndefVarNames.empty());
   FooVar.appendUndefVarNames(UndefVarNames);
@@ -67,23 +69,38 @@
   EXPECT_EQ("FOO", UndefVarNames[0]);
 }
 
-uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
+FileCheckNumExprVal doAdd(const FileCheckNumExprVal &Op1,
+                          const FileCheckNumExprVal &Op2) {
+  if (Op1.isSigned()) {
+    int64_t Val1 = Op1.getSignedValue();
+    int64_t Val2 = Op2.getSignedValue();
+
+    return FileCheckNumExprVal(Val1 + Val2);
+  } else {
+    uint64_t Val1 = Op1.getUnsignedValue();
+    uint64_t Val2 = Op2.getUnsignedValue();
+
+    return FileCheckNumExprVal(Val1 + Val2);
+  }
+}
 
 TEST_F(FileCheckTest, BinopEvalUndef) {
   auto FooNumExpr = FileCheckNumExpr(nullptr, FmtUnsigned);
   auto FooVar =
       std::make_shared<FileCheckNumericVariable>("FOO", &FooNumExpr, 1);
-  FooVar->setValue((uint64_t)42);
+  FileCheckNumExprVal LifeAnswer = FileCheckNumExprVal((uint64_t)42);
+  FooVar->setValue(LifeAnswer);
   auto BarNumExpr = FileCheckNumExpr(nullptr, FmtUnsigned);
   auto BarVar =
       std::make_shared<FileCheckNumericVariable>("BAR", &BarNumExpr, 2);
-  BarVar->setValue((uint64_t)18);
+  FileCheckNumExprVal OneEight = FileCheckNumExprVal((uint64_t)18);
+  BarVar->setValue(OneEight);
   auto Binop = new FileCheckASTBinop(doAdd, FooVar, BarVar);
 
   // Defined variable: eval returns right value, no undef variable returned.
-  llvm::Optional<uint64_t> Value = Binop->eval();
-  EXPECT_TRUE(Value);
-  EXPECT_EQ((uint64_t)60, *Value);
+  FileCheckNumExprVal Value = Binop->eval();
+  EXPECT_TRUE(Value.isValid());
+  EXPECT_EQ((uint64_t)60, Value.getUnsignedValue());
   std::vector<StringRef> UndefVarNames;
   Binop->appendUndefVarNames(UndefVarNames);
   EXPECT_TRUE(UndefVarNames.empty());
@@ -91,7 +108,7 @@
   // 1 undefined variable: eval fails, undef variable returned.
   FooVar->clearValue();
   Value = Binop->eval();
-  EXPECT_FALSE(Value);
+  EXPECT_FALSE(Value.isValid());
   Binop->appendUndefVarNames(UndefVarNames);
   EXPECT_EQ(1U, UndefVarNames.size());
   EXPECT_EQ("FOO", UndefVarNames[0]);
@@ -99,7 +116,7 @@
   // 2 undefined variables: eval fails, undef variables returned.
   BarVar->clearValue();
   Value = Binop->eval();
-  EXPECT_FALSE(Value);
+  EXPECT_FALSE(Value.isValid());
   UndefVarNames.clear();
   Binop->appendUndefVarNames(UndefVarNames);
   EXPECT_EQ(2U, UndefVarNames.size());
@@ -366,7 +383,8 @@
   // getUndefVarNames does not return any variable.
   auto NumVarExpr = FileCheckNumExpr(nullptr, FmtUnsigned);
   auto NumVar = std::make_shared<FileCheckNumericVariable>("N", &NumVarExpr, 1);
-  NumVar->setValue(42);
+  FileCheckNumExprVal LifeAnswer = FileCheckNumExprVal((uint64_t)42);
+  NumVar->setValue(LifeAnswer);
   FileCheckNumExpr NumExpr = FileCheckNumExpr(NumVar, FmtUnsigned);
   Substitution = FileCheckPatternSubstitution(&Context, "N", &NumExpr, 12);
   llvm::Optional<std::string> Value = Substitution.getResult();
@@ -421,9 +439,10 @@
 
   // Undef var in numeric expression substitution with defined variable is
   // empty.
+  FileCheckNumExprVal LifeAnswer = FileCheckNumExprVal((uint64_t)42);
   auto LineVar =
-      std::make_shared<FileCheckNumericVariable>("@LINE", (uint64_t)42);
-  auto Zero = std::make_shared<FileCheckNumExprLiteral>(0);
+      std::make_shared<FileCheckNumericVariable>("@LINE", LifeAnswer);
+  auto Zero = std::make_shared<FileCheckNumExprLiteral>((uint64_t)0);
   auto Binop = std::make_shared<FileCheckASTBinop>(doAdd, LineVar, Zero);
   FileCheckNumExpr NumExpr = FileCheckNumExpr(Binop, FmtUnsigned);
   Substitution = FileCheckPatternSubstitution(&Context, "@LINE", &NumExpr, 12);
@@ -509,9 +528,9 @@
   EXPECT_TRUE(LocalVar);
   EXPECT_EQ(*LocalVar, "FOO");
   EXPECT_TRUE(NumExpr);
-  llvm::Optional<uint64_t> NumExprVal = NumExpr->getAST()->eval();
-  EXPECT_TRUE(NumExprVal);
-  EXPECT_EQ(*NumExprVal, 18U);
+  FileCheckNumExprVal NumExprVal = NumExpr->getAST()->eval();
+  EXPECT_TRUE(NumExprVal.isValid());
+  EXPECT_EQ(NumExprVal.getSignedValue(), 18U);
   EXPECT_TRUE(EmptyVar);
   EXPECT_EQ(*EmptyVar, "");
   EXPECT_FALSE(UnknownVar);
@@ -521,7 +540,7 @@
   LocalVar = Cxt.getPatternVarValue(LocalVarStr);
   EXPECT_FALSE(LocalVar);
   // Check eval fails even if we kept a pointer to the numeric expression.
-  EXPECT_FALSE(NumExpr->getAST()->eval());
+  EXPECT_FALSE(NumExpr->getAST()->eval().isValid());
   P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
   NumExpr = P.parseNumericExpression(LocalNumVarRef, DefinedNumericVariable,
                                      false /*Legacy*/, SM);
@@ -544,8 +563,8 @@
                                      false /*Legacy*/, SM);
   EXPECT_TRUE(NumExpr);
   NumExprVal = NumExpr->getAST()->eval();
-  EXPECT_TRUE(NumExprVal);
-  EXPECT_EQ(*NumExprVal, 36U);
+  EXPECT_TRUE(NumExprVal.isValid());
+  EXPECT_EQ(NumExprVal.getSignedValue(), 36U);
 
   // Clear local variables and check global variables remain defined.
   Cxt.clearLocalVars();
@@ -556,7 +575,7 @@
                                      false /*Legacy*/, SM);
   EXPECT_TRUE(NumExpr);
   NumExprVal = NumExpr->getAST()->eval();
-  EXPECT_TRUE(NumExprVal);
-  EXPECT_EQ(*NumExprVal, 36U);
+  EXPECT_TRUE(NumExprVal.isValid());
+  EXPECT_EQ(NumExprVal.getSignedValue(), 36U);
 }
 } // namespace