[llvm] 23ac16c - FileCheck [10/12]: Add support for signed numeric values

Thomas Preud'homme via llvm-commits llvm-commits at lists.llvm.org
Thu May 28 02:45:49 PDT 2020


Author: Thomas Preud'homme
Date: 2020-05-28T10:44:21+01:00
New Revision: 23ac16cf9bd4cc0bb434efcf6385baf083a2ff7b

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

LOG: FileCheck [10/12]: Add support for signed numeric values

Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch adds support signed numeric
values, thus allowing negative numeric values.

As such, the patch adds a new class to represent a signed or unsigned
value and add the logic for type promotion and type conversion in
numeric expression mixing signed and unsigned values. It also adds
the %d format specifier to represent signed value.

Finally, it also adds underflow and overflow detection when performing a
binary operation.

Copyright:
    - Linaro (changes up to diff 183612 of revision D55940)
    - GraphCore (changes in later versions of revision D55940 and
                 in new revision created off D55940)

Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson

Reviewed By: jhenderson, arichardson

Subscribers: MaskRay, hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, kristina, hfinkel, rogfer01, JonChesterfield

Tags: #llvm

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

Added: 
    

Modified: 
    llvm/docs/CommandGuide/FileCheck.rst
    llvm/lib/Support/FileCheck.cpp
    llvm/lib/Support/FileCheckImpl.h
    llvm/test/FileCheck/numeric-expression.txt
    llvm/unittests/Support/FileCheckTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/CommandGuide/FileCheck.rst b/llvm/docs/CommandGuide/FileCheck.rst
index d8a2e343026b..0512133f2e99 100644
--- a/llvm/docs/CommandGuide/FileCheck.rst
+++ b/llvm/docs/CommandGuide/FileCheck.rst
@@ -660,8 +660,8 @@ The syntax to define a numeric variable is ``[[#%<fmtspec>,<NUMVAR>:]]`` where:
 
 * ``%<fmtspec>`` is an optional scanf-style matching format specifier to
   indicate what number format to match (e.g. hex number).  Currently accepted
-  format specifiers are ``%u``, ``%x`` and ``%X``.  If absent, the format
-  specifier defaults to ``%u``.
+  format specifiers 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.
@@ -692,10 +692,11 @@ The syntax of a numeric substitution is ``[[#%<fmtspec>,<expr>]]`` where:
   * an expression followed by an operator and a numeric operand.
 
   A numeric operand is a previously defined numeric variable, or an integer
-  literal. The supported operators are ``+`` and ``-``. Spaces are accepted
-  before, after and between any of these elements.
-  There is currently no support for operator precendence, but parentheses can
-  be used to change the evaluation order.
+  literal and have a 64-bit precision. The supported operators are ``+`` and
+  ``-``. Spaces are accepted before, after and between any of these elements.
+  Overflow and underflow are rejected. There is currently no support for
+  operator precendence, but parentheses can be used to change the evaluation
+  order.
 
 For example:
 

diff  --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp
index 300eea865f91..454f38132f6b 100644
--- a/llvm/lib/Support/FileCheck.cpp
+++ b/llvm/lib/Support/FileCheck.cpp
@@ -17,6 +17,7 @@
 #include "FileCheckImpl.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/CheckedArithmetic.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <cstdint>
 #include <list>
@@ -31,6 +32,8 @@ StringRef ExpressionFormat::toString() const {
     return StringRef("<none>");
   case Kind::Unsigned:
     return StringRef("%u");
+  case Kind::Signed:
+    return StringRef("%d");
   case Kind::HexUpper:
     return StringRef("%X");
   case Kind::HexLower:
@@ -43,6 +46,8 @@ Expected<StringRef> ExpressionFormat::getWildcardRegex() const {
   switch (Value) {
   case Kind::Unsigned:
     return StringRef("[0-9]+");
+  case Kind::Signed:
+    return StringRef("-?[0-9]+");
   case Kind::HexUpper:
     return StringRef("[0-9A-F]+");
   case Kind::HexLower:
@@ -54,43 +59,188 @@ Expected<StringRef> ExpressionFormat::getWildcardRegex() const {
 }
 
 Expected<std::string>
-ExpressionFormat::getMatchingString(uint64_t IntegerValue) const {
+ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const {
+  if (Value == Kind::Signed) {
+    Expected<int64_t> SignedValue = IntegerValue.getSignedValue();
+    if (!SignedValue)
+      return SignedValue.takeError();
+    return itostr(*SignedValue);
+  }
+
+  Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue();
+  if (!UnsignedValue)
+    return UnsignedValue.takeError();
   switch (Value) {
   case Kind::Unsigned:
-    return utostr(IntegerValue);
+    return utostr(*UnsignedValue);
   case Kind::HexUpper:
-    return utohexstr(IntegerValue, /*LowerCase=*/false);
+    return utohexstr(*UnsignedValue, /*LowerCase=*/false);
   case Kind::HexLower:
-    return utohexstr(IntegerValue, /*LowerCase=*/true);
+    return utohexstr(*UnsignedValue, /*LowerCase=*/true);
   default:
     return createStringError(std::errc::invalid_argument,
                              "trying to match value with invalid format");
   }
 }
 
-Expected<uint64_t>
+Expected<ExpressionValue>
 ExpressionFormat::valueFromStringRepr(StringRef StrVal,
                                       const SourceMgr &SM) const {
+  bool ValueIsSigned = Value == Kind::Signed;
+  StringRef OverflowErrorStr = "unable to represent numeric value";
+  if (ValueIsSigned) {
+    int64_t SignedValue;
+
+    if (StrVal.getAsInteger(10, SignedValue))
+      return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr);
+
+    return ExpressionValue(SignedValue);
+  }
+
   bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower;
-  uint64_t IntegerValue;
-  if (StrVal.getAsInteger(Hex ? 16 : 10, IntegerValue))
-    return ErrorDiagnostic::get(SM, StrVal,
-                                "unable to represent numeric value");
+  uint64_t UnsignedValue;
+  if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue))
+    return ErrorDiagnostic::get(SM, StrVal, OverflowErrorStr);
 
-  return IntegerValue;
+  return ExpressionValue(UnsignedValue);
 }
 
-Expected<uint64_t> NumericVariableUse::eval() const {
-  Optional<uint64_t> Value = Variable->getValue();
+static int64_t getAsSigned(uint64_t UnsignedValue) {
+  // Use memcpy to reinterpret the bitpattern in Value since casting to
+  // signed is implementation-defined if the unsigned value is too big to be
+  // represented in the signed type and using an union violates type aliasing
+  // rules.
+  int64_t SignedValue;
+  memcpy(&SignedValue, &UnsignedValue, sizeof(SignedValue));
+  return SignedValue;
+}
+
+Expected<int64_t> ExpressionValue::getSignedValue() const {
+  if (Negative)
+    return getAsSigned(Value);
+
+  if (Value > std::numeric_limits<int64_t>::max())
+    return make_error<OverflowError>();
+
+  // Value is in the representable range of int64_t so we can use cast.
+  return static_cast<int64_t>(Value);
+}
+
+Expected<uint64_t> ExpressionValue::getUnsignedValue() const {
+  if (Negative)
+    return make_error<OverflowError>();
+
+  return Value;
+}
+
+ExpressionValue ExpressionValue::getAbsolute() const {
+  if (!Negative)
+    return *this;
+
+  int64_t SignedValue = getAsSigned(Value);
+  int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
+  // Absolute value can be represented as int64_t.
+  if (SignedValue >= -MaxInt64)
+    return ExpressionValue(-getAsSigned(Value));
+
+  // -X == -(max int64_t + Rem), negate each component independently.
+  SignedValue += MaxInt64;
+  uint64_t RemainingValueAbsolute = -SignedValue;
+  return ExpressionValue(MaxInt64 + RemainingValueAbsolute);
+}
+
+Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
+                                          const ExpressionValue &RightOperand) {
+  if (LeftOperand.isNegative() && RightOperand.isNegative()) {
+    int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
+    int64_t RightValue = cantFail(RightOperand.getSignedValue());
+    Optional<int64_t> Result = checkedAdd<int64_t>(LeftValue, RightValue);
+    if (!Result)
+      return make_error<OverflowError>();
+
+    return ExpressionValue(*Result);
+  }
+
+  // (-A) + B == B - A.
+  if (LeftOperand.isNegative())
+    return RightOperand - LeftOperand.getAbsolute();
+
+  // A + (-B) == A - B.
+  if (RightOperand.isNegative())
+    return LeftOperand - RightOperand.getAbsolute();
+
+  // Both values are positive at this point.
+  uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+  uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+  Optional<uint64_t> Result =
+      checkedAddUnsigned<uint64_t>(LeftValue, RightValue);
+  if (!Result)
+    return make_error<OverflowError>();
+
+  return ExpressionValue(*Result);
+}
+
+Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand,
+                                          const ExpressionValue &RightOperand) {
+  // Result will be negative and thus might underflow.
+  if (LeftOperand.isNegative() && !RightOperand.isNegative()) {
+    int64_t LeftValue = cantFail(LeftOperand.getSignedValue());
+    uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+    // Result <= -1 - (max int64_t) which overflows on 1- and 2-complement.
+    if (RightValue > std::numeric_limits<int64_t>::max())
+      return make_error<OverflowError>();
+    Optional<int64_t> Result =
+        checkedSub(LeftValue, static_cast<int64_t>(RightValue));
+    if (!Result)
+      return make_error<OverflowError>();
+
+    return ExpressionValue(*Result);
+  }
+
+  // (-A) - (-B) == B - A.
+  if (LeftOperand.isNegative())
+    return RightOperand.getAbsolute() - LeftOperand.getAbsolute();
+
+  // A - (-B) == A + B.
+  if (RightOperand.isNegative())
+    return LeftOperand + RightOperand.getAbsolute();
+
+  // Both values are positive at this point.
+  uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue());
+  uint64_t RightValue = cantFail(RightOperand.getUnsignedValue());
+  if (LeftValue >= RightValue)
+    return ExpressionValue(LeftValue - RightValue);
+  else {
+    uint64_t AbsoluteDifference = RightValue - LeftValue;
+    uint64_t MaxInt64 = std::numeric_limits<int64_t>::max();
+    // Value might underflow.
+    if (AbsoluteDifference > MaxInt64) {
+      AbsoluteDifference -= MaxInt64;
+      int64_t Result = -MaxInt64;
+      int64_t MinInt64 = std::numeric_limits<int64_t>::min();
+      // Underflow, tested by:
+      //   abs(Result + (max int64_t)) > abs((min int64_t) + (max int64_t))
+      if (AbsoluteDifference > static_cast<uint64_t>(-(MinInt64 - Result)))
+        return make_error<OverflowError>();
+      Result -= static_cast<int64_t>(AbsoluteDifference);
+      return ExpressionValue(Result);
+    }
+
+    return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference));
+  }
+}
+
+Expected<ExpressionValue> NumericVariableUse::eval() const {
+  Optional<ExpressionValue> Value = Variable->getValue();
   if (Value)
     return *Value;
 
   return make_error<UndefVarError>(getExpressionStr());
 }
 
-Expected<uint64_t> BinaryOperation::eval() const {
-  Expected<uint64_t> LeftOp = LeftOperand->eval();
-  Expected<uint64_t> RightOp = RightOperand->eval();
+Expected<ExpressionValue> BinaryOperation::eval() const {
+  Expected<ExpressionValue> LeftOp = LeftOperand->eval();
+  Expected<ExpressionValue> RightOp = RightOperand->eval();
 
   // Bubble up any error (e.g. undefined variables) in the recursive
   // evaluation.
@@ -136,7 +286,8 @@ BinaryOperation::getImplicitFormat(const SourceMgr &SM) const {
 Expected<std::string> NumericSubstitution::getResult() const {
   assert(ExpressionPointer->getAST() != nullptr &&
          "Substituting empty expression");
-  Expected<uint64_t> EvaluatedValue = ExpressionPointer->getAST()->eval();
+  Expected<ExpressionValue> EvaluatedValue =
+      ExpressionPointer->getAST()->eval();
   if (!EvaluatedValue)
     return EvaluatedValue.takeError();
   ExpressionFormat Format = ExpressionPointer->getFormat();
@@ -192,6 +343,7 @@ static char popFront(StringRef &S) {
   return C;
 }
 
+char OverflowError::ID = 0;
 char UndefVarError::ID = 0;
 char ErrorDiagnostic::ID = 0;
 char NotFoundError::ID = 0;
@@ -295,13 +447,18 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
   }
 
   // Otherwise, parse it as a literal.
-  uint64_t LiteralValue;
-  StringRef OperandExpr = Expr;
+  int64_t SignedLiteralValue;
+  uint64_t UnsignedLiteralValue;
+  StringRef SaveExpr = Expr;
+  // Accept both signed and unsigned literal, default to signed literal.
   if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,
-                           LiteralValue)) {
-    return std::make_unique<ExpressionLiteral>(
-        OperandExpr.drop_back(Expr.size()), LiteralValue);
-  }
+                           UnsignedLiteralValue))
+    return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
+                                               UnsignedLiteralValue);
+  Expr = SaveExpr;
+  if (AO == AllowedOperand::Any && !Expr.consumeInteger(0, SignedLiteralValue))
+    return std::make_unique<ExpressionLiteral>(SaveExpr.drop_back(Expr.size()),
+                                               SignedLiteralValue);
 
   return ErrorDiagnostic::get(SM, Expr,
                               "invalid operand format '" + Expr + "'");
@@ -339,14 +496,6 @@ Pattern::parseParenExpr(StringRef &Expr, Optional<size_t> LineNumber,
   return SubExprResult;
 }
 
-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;
-}
-
 Expected<std::unique_ptr<ExpressionAST>>
 Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
                     std::unique_ptr<ExpressionAST> LeftOp,
@@ -363,10 +512,10 @@ Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
   binop_eval_t EvalBinop;
   switch (Operator) {
   case '+':
-    EvalBinop = add;
+    EvalBinop = operator+;
     break;
   case '-':
-    EvalBinop = sub;
+    EvalBinop = operator-;
     break;
   default:
     return ErrorDiagnostic::get(
@@ -415,6 +564,9 @@ Expected<std::unique_ptr<Expression>> Pattern::parseNumericSubstitutionBlock(
     case 'u':
       ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Unsigned);
       break;
+    case 'd':
+      ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::Signed);
+      break;
     case 'x':
       ExplicitFormat = ExpressionFormat(ExpressionFormat::Kind::HexLower);
       break;
@@ -819,7 +971,7 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
   if (!Substitutions.empty()) {
     TmpStr = RegExStr;
     if (LineNumber)
-      Context->LineVariable->setValue(*LineNumber);
+      Context->LineVariable->setValue(ExpressionValue(*LineNumber));
 
     size_t InsertOffset = 0;
     // Substitute all string variables and expressions whose values are only
@@ -828,8 +980,18 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
     for (const auto &Substitution : Substitutions) {
       // Substitute and check for failure (e.g. use of undefined variable).
       Expected<std::string> Value = Substitution->getResult();
-      if (!Value)
-        return Value.takeError();
+      if (!Value) {
+        // Convert to an ErrorDiagnostic to get location information. This is
+        // done here rather than PrintNoMatch since now we know which
+        // substitution block caused the overflow.
+        Error Err =
+            handleErrors(Value.takeError(), [&](const OverflowError &E) {
+              return ErrorDiagnostic::get(SM, Substitution->getFromString(),
+                                          "unable to substitute variable or "
+                                          "numeric expression: overflow error");
+            });
+        return std::move(Err);
+      }
 
       // Plop it into the regex at the adjusted offset.
       TmpStr.insert(TmpStr.begin() + Substitution->getIndex() + InsertOffset,
@@ -870,7 +1032,8 @@ Expected<size_t> Pattern::match(StringRef Buffer, size_t &MatchLen,
 
     StringRef MatchedValue = MatchInfo[CaptureParenGroup];
     ExpressionFormat Format = DefinedNumericVariable->getImplicitFormat();
-    Expected<uint64_t> Value = Format.valueFromStringRepr(MatchedValue, SM);
+    Expected<ExpressionValue> Value =
+        Format.valueFromStringRepr(MatchedValue, SM);
     if (!Value)
       return Value.takeError();
     DefinedNumericVariable->setValue(*Value);
@@ -914,17 +1077,20 @@ void Pattern::printSubstitutions(const SourceMgr &SM, StringRef Buffer,
       // variables it uses.
       if (!MatchedValue) {
         bool UndefSeen = false;
-        handleAllErrors(MatchedValue.takeError(), [](const NotFoundError &E) {},
-                        // Handled in PrintNoMatch().
-                        [](const ErrorDiagnostic &E) {},
-                        [&](const UndefVarError &E) {
-                          if (!UndefSeen) {
-                            OS << "uses undefined variable(s):";
-                            UndefSeen = true;
-                          }
-                          OS << " ";
-                          E.log(OS);
-                        });
+        handleAllErrors(
+            MatchedValue.takeError(), [](const NotFoundError &E) {},
+            // Handled in PrintNoMatch().
+            [](const ErrorDiagnostic &E) {},
+            // Handled in match().
+            [](const OverflowError &E) {},
+            [&](const UndefVarError &E) {
+              if (!UndefSeen) {
+                OS << "uses undefined variable(s):";
+                UndefSeen = true;
+              }
+              OS << " ";
+              E.log(OS);
+            });
       } else {
         // Substitution succeeded. Print substituted value.
         OS << "with \"";
@@ -2086,7 +2252,7 @@ Error FileCheckPatternContext::defineCmdlineVariables(
       // to, since the expression of a command-line variable definition should
       // only use variables defined earlier on the command-line. If not, this
       // is an error and we report it.
-      Expected<uint64_t> Value = Expression->getAST()->eval();
+      Expected<ExpressionValue> Value = Expression->getAST()->eval();
       if (!Value) {
         Errs = joinErrors(std::move(Errs), Value.takeError());
         continue;

diff  --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h
index f4f2fc21a208..068de3da1c69 100644
--- a/llvm/lib/Support/FileCheckImpl.h
+++ b/llvm/lib/Support/FileCheckImpl.h
@@ -31,6 +31,8 @@ namespace llvm {
 // Numeric substitution handling code.
 //===----------------------------------------------------------------------===//
 
+class ExpressionValue;
+
 /// Type representing the format an expression value should be textualized into
 /// for matching. Used to represent both explicit format specifiers as well as
 /// implicit format from using numeric variables.
@@ -41,6 +43,8 @@ struct ExpressionFormat {
     NoFormat,
     /// Value is an unsigned integer and should be printed as a decimal number.
     Unsigned,
+    /// Value is a signed integer and should be printed as a decimal number.
+    Signed,
     /// Value should be printed as an uppercase hex number.
     HexUpper,
     /// Value should be printed as a lowercase hex number.
@@ -80,17 +84,64 @@ struct ExpressionFormat {
   Expected<StringRef> getWildcardRegex() const;
 
   /// \returns the string representation of \p Value in the format represented
-  /// by this instance, or an error if the format is NoFormat.
-  Expected<std::string> getMatchingString(uint64_t Value) const;
+  /// by this instance, or an error if conversion to this format failed or the
+  /// format is NoFormat.
+  Expected<std::string> getMatchingString(ExpressionValue Value) const;
 
   /// \returns the value corresponding to string representation \p StrVal
   /// according to the matching format represented by this instance or an error
   /// with diagnostic against \p SM if \p StrVal does not correspond to a valid
   /// and representable value.
-  Expected<uint64_t> valueFromStringRepr(StringRef StrVal,
-                                         const SourceMgr &SM) const;
+  Expected<ExpressionValue> valueFromStringRepr(StringRef StrVal,
+                                                const SourceMgr &SM) const;
 };
 
+/// Class to represent an overflow error that might result when manipulating a
+/// value.
+class OverflowError : public ErrorInfo<OverflowError> {
+public:
+  static char ID;
+
+  std::error_code convertToErrorCode() const override {
+    return std::make_error_code(std::errc::value_too_large);
+  }
+
+  void log(raw_ostream &OS) const override { OS << "overflow error"; }
+};
+
+/// Class representing a numeric value.
+class ExpressionValue {
+private:
+  uint64_t Value;
+  bool Negative;
+
+public:
+  template <class T>
+  explicit ExpressionValue(T Val) : Value(Val), Negative(Val < 0) {}
+
+  /// Returns true if value is signed and negative, false otherwise.
+  bool isNegative() const { return Negative; }
+
+  /// \returns the value as a signed integer or an error if the value is out of
+  /// range.
+  Expected<int64_t> getSignedValue() const;
+
+  /// \returns the value as an unsigned integer or an error if the value is out
+  /// of range.
+  Expected<uint64_t> getUnsignedValue() const;
+
+  /// \returns an unsigned ExpressionValue instance whose value is the absolute
+  /// value to this object's value.
+  ExpressionValue getAbsolute() const;
+};
+
+/// Performs operation and \returns its result or an error in case of failure,
+/// such as if an overflow occurs.
+Expected<ExpressionValue> operator+(const ExpressionValue &Lhs,
+                                    const ExpressionValue &Rhs);
+Expected<ExpressionValue> operator-(const ExpressionValue &Lhs,
+                                    const ExpressionValue &Rhs);
+
 /// Base class representing the AST of a given expression.
 class ExpressionAST {
 private:
@@ -105,7 +156,7 @@ class ExpressionAST {
 
   /// Evaluates and \returns the value of the expression represented by this
   /// AST or an error if evaluation fails.
-  virtual Expected<uint64_t> eval() const = 0;
+  virtual Expected<ExpressionValue> eval() const = 0;
 
   /// \returns either the implicit format of this AST, a diagnostic against
   /// \p SM if implicit formats of the AST's components conflict, or NoFormat
@@ -121,16 +172,15 @@ class ExpressionAST {
 class ExpressionLiteral : public ExpressionAST {
 private:
   /// Actual value of the literal.
-  uint64_t Value;
+  ExpressionValue Value;
 
 public:
-  /// Constructs a literal with the specified value parsed from
-  /// \p ExpressionStr.
-  ExpressionLiteral(StringRef ExpressionStr, uint64_t Val)
+  template <class T>
+  explicit ExpressionLiteral(StringRef ExpressionStr, T Val)
       : ExpressionAST(ExpressionStr), Value(Val) {}
 
   /// \returns the literal's value.
-  Expected<uint64_t> eval() const override { return Value; }
+  Expected<ExpressionValue> eval() const override { return Value; }
 };
 
 /// Class to represent an undefined variable error, which quotes that
@@ -190,7 +240,7 @@ class NumericVariable {
   ExpressionFormat ImplicitFormat;
 
   /// Value of numeric variable, if defined, or None otherwise.
-  Optional<uint64_t> Value;
+  Optional<ExpressionValue> Value;
 
   /// Line number where this variable is defined, or None if defined before
   /// input is parsed. Used to determine whether a variable is defined on the
@@ -213,10 +263,10 @@ class NumericVariable {
   ExpressionFormat getImplicitFormat() const { return ImplicitFormat; }
 
   /// \returns this variable's value.
-  Optional<uint64_t> getValue() const { return Value; }
+  Optional<ExpressionValue> getValue() const { return Value; }
 
   /// Sets value of this numeric variable to \p NewValue.
-  void setValue(uint64_t NewValue) { Value = NewValue; }
+  void setValue(ExpressionValue NewValue) { Value = NewValue; }
 
   /// Clears value of this numeric variable, regardless of whether it is
   /// currently defined or not.
@@ -238,7 +288,7 @@ class NumericVariableUse : public ExpressionAST {
   NumericVariableUse(StringRef Name, NumericVariable *Variable)
       : ExpressionAST(Name), Variable(Variable) {}
   /// \returns the value of the variable referenced by this instance.
-  Expected<uint64_t> eval() const override;
+  Expected<ExpressionValue> eval() const override;
 
   /// \returns implicit format of this numeric variable.
   Expected<ExpressionFormat>
@@ -248,7 +298,8 @@ class NumericVariableUse : public ExpressionAST {
 };
 
 /// Type of functions evaluating a given binary operation.
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
+using binop_eval_t = Expected<ExpressionValue> (*)(const ExpressionValue &,
+                                                   const ExpressionValue &);
 
 /// Class representing a single binary operation in the AST of an expression.
 class BinaryOperation : public ExpressionAST {
@@ -275,7 +326,7 @@ class BinaryOperation : public ExpressionAST {
   /// using EvalBinop on the result of recursively evaluating the operands.
   /// \returns the expression value or an error if an undefined numeric
   /// variable is used in one of the operands.
-  Expected<uint64_t> eval() const override;
+  Expected<ExpressionValue> eval() const override;
 
   /// \returns the implicit format of this AST, if any, a diagnostic against
   /// \p SM if the implicit formats of the AST's components conflict, or no

diff  --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt
index 3d33e64a0a9e..d5b4db7d30ea 100644
--- a/llvm/test/FileCheck/numeric-expression.txt
+++ b/llvm/test/FileCheck/numeric-expression.txt
@@ -19,8 +19,9 @@ REDEF NO SPC  // CHECK-LABEL: REDEF
 
 ; Numeric variable definition with explicit matching format.
 DEF FMT  // CHECK-LABEL: DEF FMT
-c  // CHECK-NEXT: {{^}}[[#%x,LHEX:]]
-D  // CHECK-NEXT: {{^}}[[#%X,UHEX:]]
+c    // CHECK-NEXT: {{^}}[[#%x,LHEX:]]
+D    // CHECK-NEXT: {{^}}[[#%X,UHEX:]]
+-30  // CHECK-NEXT: {{^}}[[#%d,SIGN:]]
 
 ; Numeric variable definition with explicit matching format with 
diff erent
 ; spacing.
@@ -64,6 +65,10 @@ E   // CHECK-NEXT: {{^}}[[#%X,UHEX+1]]
 C   // CHECK-NEXT: {{^}}[[#%X,UHEX-1]]
 1B  // CHECK-NEXT: {{^}}[[#%X,UHEX+0xe]]
 1B  // CHECK-NEXT: {{^}}[[#%X,UHEX+0xE]]
+-30 // CHECK-NEXT: {{^}}[[#%d,SIGN]]
+-29 // CHECK-NEXT: {{^}}[[#%d,SIGN+1]]
+-31 // CHECK-NEXT: {{^}}[[#%d,SIGN-1]]
+42  // CHECK-NEXT: {{^}}[[#%d,SIGN+72]]
 11  // CHECK-NEXT: {{^}}[[#%u,UNSIa]]
 11  // CHECK-NEXT: {{^}}[[#%u,UNSIb]]
 11  // CHECK-NEXT: {{^}}[[#%u,UNSIc]]
@@ -104,6 +109,9 @@ E   // CHECK-NEXT: {{^}}[[#UHEX+1]]
 C   // CHECK-NEXT: {{^}}[[#UHEX-1]]
 1B  // CHECK-NEXT: {{^}}[[#UHEX+0xe]]
 1B  // CHECK-NEXT: {{^}}[[#UHEX+0xE]]
+-30 // CHECK-NEXT: {{^}}[[#SIGN]]
+-29 // CHECK-NEXT: {{^}}[[#SIGN+1]]
+-31 // CHECK-NEXT: {{^}}[[#SIGN-1]]
 
 ; Numeric expressions using variables defined on other lines and an immediate
 ; interpreted as an unsigned value.
@@ -118,10 +126,16 @@ CHECK-NEXT: [[#UNSI+0x8000000000000000]]
 USE CONV FMT IMPL MATCH  // CHECK-LABEL: USE CONV FMT IMPL MATCH
 b   // CHECK-NEXT: {{^}}[[# %x, UNSI]]
 B   // CHECK-NEXT: {{^}}[[# %X, UNSI]]
+-1  // CHECK-NEXT: {{^}}[[# %d, UNSI-12]]
 12  // CHECK-NEXT: {{^}}[[# %u, LHEX]]
 C   // CHECK-NEXT: {{^}}[[# %X, LHEX]]
+-2  // CHECK-NEXT: {{^}}[[# %d, LHEX-14]]
 13  // CHECK-NEXT: {{^}}[[# %u, UHEX]]
 d   // CHECK-NEXT: {{^}}[[# %x, UHEX]]
+-5  // CHECK-NEXT: {{^}}[[# %d, UHEX-18]]
+15  // CHECK-NEXT: {{^}}[[# %u, SIGN+45]]
+f   // CHECK-NEXT: {{^}}[[# %x, SIGN+45]]
+F   // CHECK-NEXT: {{^}}[[# %X, SIGN+45]]
 
 ; Conflicting implicit format.
 RUN: %ProtectFileCheckOutput \
@@ -329,3 +343,27 @@ REDEF-NEW-FMT-NEXT: [[#%X,UNSI:]]
 REDEF-NEW-FMT-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: format 
diff erent from previous variable definition
 REDEF-NEW-FMT-MSG-NEXT: {{R}}EDEF-NEW-FMT-NEXT: {{\[\[#%X,UNSI:\]\]}}
 REDEF-NEW-FMT-MSG-NEXT:    {{^}}                              ^{{$}}
+
+; Numeric expression with overflow.
+RUN: not FileCheck --check-prefix OVERFLOW --input-file %s %s 2>&1 \
+RUN:   | FileCheck --check-prefix OVERFLOW-MSG --strict-whitespace %s
+
+OVERFLOW
+BIGVAR=10000000000000000
+OVERFLOW-LABEL: OVERFLOW
+OVERFLOW-NEXT: BIGVAR: [[#BIGVAR:0x8000000000000000+0x8000000000000000]]
+OVERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:27: 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 --strict-whitespace %s
+
+UNDERFLOW
+TINYVAR=-10000000000000000
+UNDERFLOW-LABEL: UNDERFLOW
+UNDERFLOW-NEXT: TINYVAR: [[#%d,TINYVAR:-0x8000000000000000-0x8000000000000000]]
+UNDERFLOW-MSG: numeric-expression.txt:[[#@LINE-1]]:29: 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
index 75b7fba8759d..54646a036f73 100644
--- a/llvm/unittests/Support/FileCheckTest.cpp
+++ b/llvm/unittests/Support/FileCheckTest.cpp
@@ -88,13 +88,16 @@ struct ExpressionFormatParameterisedFixture
   bool AllowUpperHex;
 };
 
+const uint64_t MaxUint64 = std::numeric_limits<uint64_t>::max();
+
 TEST_P(ExpressionFormatParameterisedFixture, Format) {
   SourceMgr SM;
   ExpressionFormat Format(Kind);
+  bool Signed = Kind == ExpressionFormat::Kind::Signed;
 
   Expected<StringRef> WildcardPattern = Format.getWildcardRegex();
   ASSERT_THAT_EXPECTED(WildcardPattern, Succeeded());
-  Regex WildcardRegex(*WildcardPattern);
+  Regex WildcardRegex((Twine("^") + *WildcardPattern).str());
   ASSERT_TRUE(WildcardRegex.isValid());
   // Does not match empty string.
   EXPECT_FALSE(WildcardRegex.match(""));
@@ -103,6 +106,14 @@ TEST_P(ExpressionFormatParameterisedFixture, Format) {
   StringRef DecimalDigits = "0123456789";
   ASSERT_TRUE(WildcardRegex.match(DecimalDigits, &Matches));
   EXPECT_EQ(Matches[0], DecimalDigits);
+  // Matches negative digits.
+  StringRef MinusFortyTwo = "-42";
+  bool MatchSuccess = WildcardRegex.match(MinusFortyTwo, &Matches);
+  if (Signed) {
+    ASSERT_TRUE(MatchSuccess);
+    EXPECT_EQ(Matches[0], MinusFortyTwo);
+  } else
+    EXPECT_FALSE(MatchSuccess);
   // Check non digits or digits with wrong casing are not matched.
   if (AllowHex) {
     StringRef HexOnlyDigits[] = {"abcdef", "ABCDEF"};
@@ -121,42 +132,75 @@ TEST_P(ExpressionFormatParameterisedFixture, Format) {
     EXPECT_FALSE(WildcardRegex.match("A"));
   }
 
-  Expected<std::string> MatchingString = Format.getMatchingString(0U);
+  Expected<std::string> MatchingString =
+      Format.getMatchingString(ExpressionValue(0u));
   ASSERT_THAT_EXPECTED(MatchingString, Succeeded());
   EXPECT_EQ(*MatchingString, "0");
-  MatchingString = Format.getMatchingString(9U);
+  MatchingString = Format.getMatchingString(ExpressionValue(9u));
   ASSERT_THAT_EXPECTED(MatchingString, Succeeded());
   EXPECT_EQ(*MatchingString, "9");
-  Expected<std::string> TenMatchingString = Format.getMatchingString(10U);
+  MatchingString = Format.getMatchingString(ExpressionValue(-5));
+  if (Signed) {
+    ASSERT_THAT_EXPECTED(MatchingString, Succeeded());
+    EXPECT_EQ(*MatchingString, "-5");
+  } else {
+    // Error message tested in ExpressionValue unit tests.
+    EXPECT_THAT_EXPECTED(MatchingString, Failed());
+  }
+  Expected<std::string> MaxUint64MatchingString =
+      Format.getMatchingString(ExpressionValue(MaxUint64));
+  Expected<std::string> TenMatchingString =
+      Format.getMatchingString(ExpressionValue(10u));
   ASSERT_THAT_EXPECTED(TenMatchingString, Succeeded());
-  Expected<std::string> FifteenMatchingString = Format.getMatchingString(15U);
+  Expected<std::string> FifteenMatchingString =
+      Format.getMatchingString(ExpressionValue(15u));
   ASSERT_THAT_EXPECTED(FifteenMatchingString, Succeeded());
   StringRef ExpectedTenMatchingString, ExpectedFifteenMatchingString;
+  std::string MaxUint64Str;
   if (AllowHex) {
     if (AllowUpperHex) {
+      MaxUint64Str = "FFFFFFFFFFFFFFFF";
       ExpectedTenMatchingString = "A";
       ExpectedFifteenMatchingString = "F";
     } else {
+      MaxUint64Str = "ffffffffffffffff";
       ExpectedTenMatchingString = "a";
       ExpectedFifteenMatchingString = "f";
     }
   } else {
+    MaxUint64Str = std::to_string(MaxUint64);
     ExpectedTenMatchingString = "10";
     ExpectedFifteenMatchingString = "15";
   }
+  if (Signed) {
+    // Error message tested in ExpressionValue unit tests.
+    EXPECT_THAT_EXPECTED(MaxUint64MatchingString, Failed());
+  } else {
+    ASSERT_THAT_EXPECTED(MaxUint64MatchingString, Succeeded());
+    EXPECT_EQ(*MaxUint64MatchingString, MaxUint64Str);
+  }
   EXPECT_EQ(*TenMatchingString, ExpectedTenMatchingString);
   EXPECT_EQ(*FifteenMatchingString, ExpectedFifteenMatchingString);
 
   StringRef BufferizedValidValueStr = bufferize(SM, "0");
-  Expected<uint64_t> Val =
+  Expected<ExpressionValue> Val =
       Format.valueFromStringRepr(BufferizedValidValueStr, SM);
   ASSERT_THAT_EXPECTED(Val, Succeeded());
-  EXPECT_EQ(*Val, 0U);
+  EXPECT_EQ(cantFail(Val->getSignedValue()), 0);
   BufferizedValidValueStr = bufferize(SM, "9");
   Val = Format.valueFromStringRepr(BufferizedValidValueStr, SM);
   ASSERT_THAT_EXPECTED(Val, Succeeded());
-  EXPECT_EQ(*Val, 9U);
-  StringRef BufferizedTenStr, BufferizedInvalidTenStr, BufferizedFifteenStr;
+  EXPECT_EQ(cantFail(Val->getSignedValue()), 9);
+  StringRef BufferizedMinusFiveStr = bufferize(SM, "-5");
+  Val = Format.valueFromStringRepr(BufferizedMinusFiveStr, SM);
+  StringRef OverflowErrorStr = "unable to represent numeric value";
+  if (Signed) {
+    ASSERT_THAT_EXPECTED(Val, Succeeded());
+    EXPECT_EQ(cantFail(Val->getSignedValue()), -5);
+  } else
+    expectDiagnosticError(OverflowErrorStr, Val.takeError());
+  StringRef BufferizedMaxUint64Str, BufferizedTenStr, BufferizedInvalidTenStr,
+      BufferizedFifteenStr;
   StringRef TenStr, FifteenStr, InvalidTenStr;
   if (AllowHex) {
     if (AllowUpperHex) {
@@ -173,19 +217,27 @@ TEST_P(ExpressionFormatParameterisedFixture, Format) {
     FifteenStr = "15";
     InvalidTenStr = "A";
   }
+  BufferizedMaxUint64Str = bufferize(SM, MaxUint64Str);
+  Val = Format.valueFromStringRepr(BufferizedMaxUint64Str, SM);
+  if (Signed)
+    expectDiagnosticError(OverflowErrorStr, Val.takeError());
+  else {
+    ASSERT_THAT_EXPECTED(Val, Succeeded());
+    EXPECT_EQ(cantFail(Val->getUnsignedValue()), MaxUint64);
+  }
   BufferizedTenStr = bufferize(SM, TenStr);
   Val = Format.valueFromStringRepr(BufferizedTenStr, SM);
   ASSERT_THAT_EXPECTED(Val, Succeeded());
-  EXPECT_EQ(*Val, 10U);
+  EXPECT_EQ(cantFail(Val->getSignedValue()), 10);
   BufferizedFifteenStr = bufferize(SM, FifteenStr);
   Val = Format.valueFromStringRepr(BufferizedFifteenStr, SM);
   ASSERT_THAT_EXPECTED(Val, Succeeded());
-  EXPECT_EQ(*Val, 15U);
+  EXPECT_EQ(cantFail(Val->getSignedValue()), 15);
   // Wrong casing is not tested because valueFromStringRepr() relies on
   // StringRef's getAsInteger() which does not allow to restrict casing.
   BufferizedInvalidTenStr = bufferize(SM, InvalidTenStr);
   expectDiagnosticError(
-      "unable to represent numeric value",
+      OverflowErrorStr,
       Format.valueFromStringRepr(bufferize(SM, "G"), SM).takeError());
 
   // Check boolean operator.
@@ -197,6 +249,8 @@ INSTANTIATE_TEST_CASE_P(
     ::testing::Values(
         std::make_tuple(ExpressionFormat::Kind::Unsigned, /*AllowHex=*/false,
                         /*AllowUpperHex=*/false),
+        std::make_tuple(ExpressionFormat::Kind::Signed, /*AllowHex=*/false,
+                        /*AllowUpperHex=*/false),
         std::make_tuple(ExpressionFormat::Kind::HexLower, /*AllowHex=*/true,
                         /*AllowUpperHex=*/false),
         std::make_tuple(ExpressionFormat::Kind::HexUpper, /*AllowHex=*/true,
@@ -206,8 +260,9 @@ TEST_F(FileCheckTest, NoFormatProperties) {
   ExpressionFormat NoFormat(ExpressionFormat::Kind::NoFormat);
   expectError<StringError>("trying to match value with invalid format",
                            NoFormat.getWildcardRegex().takeError());
-  expectError<StringError>("trying to match value with invalid format",
-                           NoFormat.getMatchingString(18).takeError());
+  expectError<StringError>(
+      "trying to match value with invalid format",
+      NoFormat.getMatchingString(ExpressionValue(18u)).takeError());
   EXPECT_FALSE(bool(NoFormat));
 }
 
@@ -238,31 +293,221 @@ TEST_F(FileCheckTest, FormatKindEqualityOperators) {
   EXPECT_FALSE(NoFormat != ExpressionFormat::Kind::NoFormat);
 }
 
+template <class T1, class T2>
+static Expected<ExpressionValue> doValueOperation(binop_eval_t Operation,
+                                                  T1 LeftValue, T2 RightValue) {
+  ExpressionValue LeftOperand(LeftValue);
+  ExpressionValue RightOperand(RightValue);
+  return Operation(LeftOperand, RightOperand);
+}
+
+template <class T>
+static void expectValueEqual(ExpressionValue ActualValue, T ExpectedValue) {
+  EXPECT_EQ(ExpectedValue < 0, ActualValue.isNegative());
+  if (ExpectedValue < 0) {
+    Expected<int64_t> SignedActualValue = ActualValue.getSignedValue();
+    ASSERT_THAT_EXPECTED(SignedActualValue, Succeeded());
+    EXPECT_EQ(*SignedActualValue, static_cast<int64_t>(ExpectedValue));
+  } else {
+    Expected<uint64_t> UnsignedActualValue = ActualValue.getUnsignedValue();
+    ASSERT_THAT_EXPECTED(UnsignedActualValue, Succeeded());
+    EXPECT_EQ(*UnsignedActualValue, static_cast<uint64_t>(ExpectedValue));
+  }
+}
+
+template <class T1, class T2, class TR>
+static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
+                                       T2 RightValue, TR ResultValue) {
+  Expected<ExpressionValue> OperationResult =
+      doValueOperation(Operation, LeftValue, RightValue);
+  ASSERT_THAT_EXPECTED(OperationResult, Succeeded());
+  expectValueEqual(*OperationResult, ResultValue);
+}
+
+template <class T1, class T2>
+static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
+                                       T2 RightValue) {
+  expectError<OverflowError>(
+      "overflow error",
+      doValueOperation(Operation, LeftValue, RightValue).takeError());
+}
+
+const int64_t MinInt64 = std::numeric_limits<int64_t>::min();
+const int64_t MaxInt64 = std::numeric_limits<int64_t>::max();
+
+TEST_F(FileCheckTest, ExpressionValueGetUnsigned) {
+  // Test positive value.
+  Expected<uint64_t> UnsignedValue = ExpressionValue(10).getUnsignedValue();
+  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
+  EXPECT_EQ(*UnsignedValue, 10U);
+
+  // Test 0.
+  UnsignedValue = ExpressionValue(0).getUnsignedValue();
+  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
+  EXPECT_EQ(*UnsignedValue, 0U);
+
+  // Test max positive value.
+  UnsignedValue = ExpressionValue(MaxUint64).getUnsignedValue();
+  ASSERT_THAT_EXPECTED(UnsignedValue, Succeeded());
+  EXPECT_EQ(*UnsignedValue, MaxUint64);
+
+  // Test failure with negative value.
+  expectError<OverflowError>(
+      "overflow error", ExpressionValue(-1).getUnsignedValue().takeError());
+
+  // Test failure with min negative value.
+  expectError<OverflowError>(
+      "overflow error",
+      ExpressionValue(MinInt64).getUnsignedValue().takeError());
+}
+
+TEST_F(FileCheckTest, ExpressionValueGetSigned) {
+  // Test positive value.
+  Expected<int64_t> SignedValue = ExpressionValue(10).getSignedValue();
+  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
+  EXPECT_EQ(*SignedValue, 10);
+
+  // Test 0.
+  SignedValue = ExpressionValue(0).getSignedValue();
+  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
+  EXPECT_EQ(*SignedValue, 0);
+
+  // Test max int64_t.
+  SignedValue = ExpressionValue(MaxInt64).getSignedValue();
+  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
+  EXPECT_EQ(*SignedValue, MaxInt64);
+
+  // Test failure with too big positive value.
+  expectError<OverflowError>(
+      "overflow error", ExpressionValue(static_cast<uint64_t>(MaxInt64) + 1)
+                            .getSignedValue()
+                            .takeError());
+
+  // Test failure with max uint64_t.
+  expectError<OverflowError>(
+      "overflow error",
+      ExpressionValue(MaxUint64).getSignedValue().takeError());
+
+  // Test negative value.
+  SignedValue = ExpressionValue(-10).getSignedValue();
+  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
+  EXPECT_EQ(*SignedValue, -10);
+
+  // Test min int64_t.
+  SignedValue = ExpressionValue(MinInt64).getSignedValue();
+  ASSERT_THAT_EXPECTED(SignedValue, Succeeded());
+  EXPECT_EQ(*SignedValue, MinInt64);
+}
+
+TEST_F(FileCheckTest, ExpressionValueAbsolute) {
+  // Test positive value.
+  expectValueEqual(ExpressionValue(10).getAbsolute(), 10);
+
+  // Test 0.
+  expectValueEqual(ExpressionValue(0).getAbsolute(), 0);
+
+  // Test max uint64_t.
+  expectValueEqual(ExpressionValue(MaxUint64).getAbsolute(), MaxUint64);
+
+  // Test negative value.
+  expectValueEqual(ExpressionValue(-10).getAbsolute(), 10);
+
+  // Test absence of overflow on min int64_t.
+  expectValueEqual(ExpressionValue(MinInt64).getAbsolute(),
+                   static_cast<uint64_t>(-(MinInt64 + 10)) + 10);
+}
+
+TEST_F(FileCheckTest, ExpressionValueAddition) {
+  // Test both negative values.
+  expectOperationValueResult(operator+, -10, -10, -20);
+
+  // Test both negative values with underflow.
+  expectOperationValueResult(operator+, MinInt64, -1);
+  expectOperationValueResult(operator+, MinInt64, MinInt64);
+
+  // Test negative and positive value.
+  expectOperationValueResult(operator+, -10, 10, 0);
+  expectOperationValueResult(operator+, -10, 11, 1);
+  expectOperationValueResult(operator+, -11, 10, -1);
+
+  // Test positive and negative value.
+  expectOperationValueResult(operator+, 10, -10, 0);
+  expectOperationValueResult(operator+, 10, -11, -1);
+  expectOperationValueResult(operator+, 11, -10, 1);
+
+  // Test both positive values.
+  expectOperationValueResult(operator+, 10, 10, 20);
+
+  // Test both positive values with overflow.
+  expectOperationValueResult(operator+, MaxUint64, 1);
+  expectOperationValueResult(operator+, MaxUint64, MaxUint64);
+}
+
+TEST_F(FileCheckTest, ExpressionValueSubtraction) {
+  // Test negative value and value bigger than int64_t max.
+  expectOperationValueResult(operator-, -10, MaxUint64);
+
+  // Test negative and positive value with underflow.
+  expectOperationValueResult(operator-, MinInt64, 1);
+
+  // Test negative and positive value.
+  expectOperationValueResult(operator-, -10, 10, -20);
+
+  // Test both negative values.
+  expectOperationValueResult(operator-, -10, -10, 0);
+  expectOperationValueResult(operator-, -11, -10, -1);
+  expectOperationValueResult(operator-, -10, -11, 1);
+
+  // Test positive and negative values.
+  expectOperationValueResult(operator-, 10, -10, 20);
+
+  // Test both positive values with result positive.
+  expectOperationValueResult(operator-, 10, 5, 5);
+
+  // Test both positive values with underflow.
+  expectOperationValueResult(operator-, 0, MaxUint64);
+  expectOperationValueResult(operator-, 0,
+                             static_cast<uint64_t>(-(MinInt64 + 10)) + 11);
+
+  // Test both positive values with result < -(max int64_t)
+  expectOperationValueResult(operator-, 10,
+                             static_cast<uint64_t>(MaxInt64) + 11,
+                             -MaxInt64 - 1);
+
+  // Test both positive values with 0 > result > -(max int64_t)
+  expectOperationValueResult(operator-, 10, 11, -1);
+}
+
 TEST_F(FileCheckTest, Literal) {
   SourceMgr SM;
 
   // Eval returns the literal's value.
-  ExpressionLiteral Ten(bufferize(SM, "10"), 10);
-  Expected<uint64_t> Value = Ten.eval();
+  ExpressionLiteral Ten(bufferize(SM, "10"), 10u);
+  Expected<ExpressionValue> Value = Ten.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
-  EXPECT_EQ(10U, *Value);
+  EXPECT_EQ(10, cantFail(Value->getSignedValue()));
   Expected<ExpressionFormat> ImplicitFormat = Ten.getImplicitFormat(SM);
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::NoFormat);
 
+  // Min value can be correctly represented.
+  ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)), MinInt64);
+  Value = Min.eval();
+  ASSERT_TRUE(bool(Value));
+  EXPECT_EQ(MinInt64, cantFail(Value->getSignedValue()));
+
   // Max value can be correctly represented.
-  uint64_t MaxUint64 = std::numeric_limits<uint64_t>::max();
   ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)), MaxUint64);
   Value = Max.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
-  EXPECT_EQ(std::numeric_limits<uint64_t>::max(), *Value);
+  EXPECT_EQ(MaxUint64, cantFail(Value->getUnsignedValue()));
 }
 
 TEST_F(FileCheckTest, Expression) {
   SourceMgr SM;
 
   std::unique_ptr<ExpressionLiteral> Ten =
-      std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), 10);
+      std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), 10u);
   ExpressionLiteral *TenPtr = Ten.get();
   Expression Expr(std::move(Ten),
                   ExpressionFormat(ExpressionFormat::Kind::HexLower));
@@ -283,8 +528,6 @@ expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
   EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
 }
 
-uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
-
 TEST_F(FileCheckTest, NumericVariable) {
   SourceMgr SM;
 
@@ -299,18 +542,18 @@ TEST_F(FileCheckTest, NumericVariable) {
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
   EXPECT_FALSE(FooVar.getValue());
-  Expected<uint64_t> EvalResult = FooVarUse.eval();
+  Expected<ExpressionValue> EvalResult = FooVarUse.eval();
   expectUndefErrors({"FOO"}, EvalResult.takeError());
 
-  FooVar.setValue(42);
+  FooVar.setValue(ExpressionValue(42u));
 
   // Defined variable: getValue and eval return value set.
-  Optional<uint64_t> Value = FooVar.getValue();
+  Optional<ExpressionValue> Value = FooVar.getValue();
   ASSERT_TRUE(Value);
-  EXPECT_EQ(42U, *Value);
+  EXPECT_EQ(42, cantFail(Value->getSignedValue()));
   EvalResult = FooVarUse.eval();
   ASSERT_THAT_EXPECTED(EvalResult, Succeeded());
-  EXPECT_EQ(42U, *EvalResult);
+  EXPECT_EQ(42, cantFail(EvalResult->getSignedValue()));
 
   // Clearing variable: getValue and eval fail. Error returned by eval holds
   // the name of the cleared variable.
@@ -327,23 +570,24 @@ TEST_F(FileCheckTest, Binop) {
   StringRef FooStr = ExprStr.take_front(3);
   NumericVariable FooVar(FooStr,
                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
-  FooVar.setValue(42);
+  FooVar.setValue(ExpressionValue(42u));
   std::unique_ptr<NumericVariableUse> FooVarUse =
       std::make_unique<NumericVariableUse>(FooStr, &FooVar);
   StringRef BarStr = ExprStr.take_back(3);
   NumericVariable BarVar(BarStr,
                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 2);
-  BarVar.setValue(18);
+  BarVar.setValue(ExpressionValue(18u));
   std::unique_ptr<NumericVariableUse> BarVarUse =
       std::make_unique<NumericVariableUse>(BarStr, &BarVar);
+  binop_eval_t doAdd = operator+;
   BinaryOperation Binop(ExprStr, doAdd, std::move(FooVarUse),
                         std::move(BarVarUse));
 
   // Defined variables: eval returns right value; implicit format is as
   // expected.
-  Expected<uint64_t> Value = Binop.eval();
+  Expected<ExpressionValue> Value = Binop.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
-  EXPECT_EQ(60U, *Value);
+  EXPECT_EQ(60, cantFail(Value->getSignedValue()));
   Expected<ExpressionFormat> ImplicitFormat = Binop.getImplicitFormat(SM);
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
@@ -366,7 +610,7 @@ TEST_F(FileCheckTest, Binop) {
   StringRef EighteenStr = ExprStr.take_back(2);
   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
   std::unique_ptr<ExpressionLiteral> Eighteen =
-      std::make_unique<ExpressionLiteral>(EighteenStr, 18);
+      std::make_unique<ExpressionLiteral>(EighteenStr, 18u);
   Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse),
                           std::move(Eighteen));
   ImplicitFormat = Binop.getImplicitFormat(SM);
@@ -376,7 +620,7 @@ TEST_F(FileCheckTest, Binop) {
   FooStr = ExprStr.take_back(3);
   EighteenStr = ExprStr.take_front(2);
   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
-  Eighteen = std::make_unique<ExpressionLiteral>(EighteenStr, 18);
+  Eighteen = std::make_unique<ExpressionLiteral>(EighteenStr, 18u);
   Binop = BinaryOperation(ExprStr, doAdd, std::move(Eighteen),
                           std::move(FooVarUse));
   ImplicitFormat = Binop.getImplicitFormat(SM);
@@ -655,6 +899,13 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
 
   // Valid single operand expression.
   EXPECT_THAT_EXPECTED(Tester.parseSubst("FOO"), Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst("18"), Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MaxUint64)),
+                       Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst("0x12"), Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst("-30"), Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst(std::to_string(MinInt64)),
+                       Succeeded());
 
   // Invalid format.
   expectDiagnosticError("invalid matching format specification in expression",
@@ -697,6 +948,7 @@ TEST_F(FileCheckTest, ParseNumericSubstitutionBlock) {
 
   // Valid expression with format specifier.
   EXPECT_THAT_EXPECTED(Tester.parseSubst("%u, FOO"), Succeeded());
+  EXPECT_THAT_EXPECTED(Tester.parseSubst("%d, FOO"), Succeeded());
   EXPECT_THAT_EXPECTED(Tester.parseSubst("%x, FOO"), Succeeded());
   EXPECT_THAT_EXPECTED(Tester.parseSubst("%X, FOO"), Succeeded());
 
@@ -804,7 +1056,14 @@ TEST_F(FileCheckTest, ParsePattern) {
 TEST_F(FileCheckTest, Match) {
   PatternTester Tester;
 
+  // Check a substitution error is diagnosed.
+  ASSERT_FALSE(Tester.parsePattern("[[#%u, -1]]"));
+  expectDiagnosticError(
+      "unable to substitute variable or numeric expression: overflow error",
+      Tester.match("").takeError());
+
   // Check matching an empty expression only matches a number.
+  Tester.initNextPattern();
   ASSERT_FALSE(Tester.parsePattern("[[#]]"));
   expectNotFoundError(Tester.match("FAIL").takeError());
   EXPECT_THAT_EXPECTED(Tester.match("18"), Succeeded());
@@ -946,7 +1205,7 @@ TEST_F(FileCheckTest, Substitution) {
   // substituted for the variable's value.
   NumericVariable NVar("N", ExpressionFormat(ExpressionFormat::Kind::Unsigned),
                        1);
-  NVar.setValue(10);
+  NVar.setValue(ExpressionValue(10u));
   auto NVarUse = std::make_unique<NumericVariableUse>("N", &NVar);
   auto ExpressionN = std::make_unique<Expression>(
       std::move(NVarUse), ExpressionFormat(ExpressionFormat::Kind::HexUpper));
@@ -1056,24 +1315,24 @@ TEST_F(FileCheckTest, FileCheckContext) {
   Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
   Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
-  Expected<uint64_t> ExpressionVal = (*ExpressionPointer)->getAST()->eval();
+  Expected<ExpressionValue> ExpressionVal =
+      (*ExpressionPointer)->getAST()->eval();
   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
-  EXPECT_EQ(*ExpressionVal, 18U);
+  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 18);
   ExpressionPointer = P.parseNumericSubstitutionBlock(
       LocalNumVar2Ref, DefinedNumericVariable,
       /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
-  EXPECT_EQ(*ExpressionVal, 20U);
-  ExpressionPointer =
-      P.parseNumericSubstitutionBlock(LocalNumVar3Ref, DefinedNumericVariable,
-                                      /*IsLegacyLineExpr=*/false,
-                                      LineNumber, &Cxt, SM);
+  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 20);
+  ExpressionPointer = P.parseNumericSubstitutionBlock(
+      LocalNumVar3Ref, DefinedNumericVariable,
+      /*IsLegacyLineExpr=*/false, LineNumber, &Cxt, SM);
   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
-  EXPECT_EQ(*ExpressionVal, 12U);
+  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 12);
   ASSERT_THAT_EXPECTED(EmptyVar, Succeeded());
   EXPECT_EQ(*EmptyVar, "");
   expectUndefErrors({std::string(UnknownVarStr)}, UnknownVar.takeError());
@@ -1123,7 +1382,7 @@ TEST_F(FileCheckTest, FileCheckContext) {
   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
-  EXPECT_EQ(*ExpressionVal, 36U);
+  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 36);
 
   // Clear local variables and check global variables remain defined.
   Cxt.clearLocalVars();
@@ -1135,6 +1394,6 @@ TEST_F(FileCheckTest, FileCheckContext) {
   ASSERT_THAT_EXPECTED(ExpressionPointer, Succeeded());
   ExpressionVal = (*ExpressionPointer)->getAST()->eval();
   ASSERT_THAT_EXPECTED(ExpressionVal, Succeeded());
-  EXPECT_EQ(*ExpressionVal, 36U);
+  EXPECT_EQ(cantFail(ExpressionVal->getSignedValue()), 36);
 }
 } // namespace


        


More information about the llvm-commits mailing list