[llvm] 0726cb0 - [FileCheck, 3/4] Allow AP value for numeric expressions

Thomas Preud'homme via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 7 06:48:54 PDT 2023


Author: Thomas Preud'homme
Date: 2023-08-07T14:48:48+01:00
New Revision: 0726cb00471850ead0835e5d3806c7aef5bb0b21

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

LOG: [FileCheck, 3/4] Allow AP value for numeric expressions

Use APInt to represent numeric variables and expressions, therefore
removing overflow concerns. Only remains underflow when the format of an
expression is unsigned (incl. hex values) but the result is negative.
Note that this can only happen when substituting an expression, not when
capturing since the regex used to capture unsigned value will not include
minus sign, hence all the code removal for match propagation testing.
This is what this patch implement.

Reviewed By: arichardson

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

Added: 
    

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

Removed: 
    llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
    llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
    llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
    llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt


################################################################################
diff  --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp
index 3e4514f2545b562..b344b7176486808 100644
--- a/llvm/lib/FileCheck/FileCheck.cpp
+++ b/llvm/lib/FileCheck/FileCheck.cpp
@@ -80,16 +80,8 @@ Expected<std::string> ExpressionFormat::getWildcardRegex() const {
 Expected<std::string>
 ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const {
   APInt IntValue = IntegerValue.getAPIntValue();
-  // Error out for values that cannot be represented by the appropriate 64-bit
-  // integer (e.g. int64_t for a signed format) to keep the getter of
-  // ExpressionValue as an APInt an NFC.
-  if (Value == Kind::Signed) {
-    if (!IntValue.isSignedIntN(64))
-      return make_error<OverflowError>();
-  } else {
-    if (!IntValue.isIntN(64))
-      return make_error<OverflowError>();
-  }
+  if (Value != Kind::Signed && IntValue.isNegative())
+    return make_error<OverflowError>();
 
   unsigned Radix;
   bool UpperCase = false;
@@ -129,6 +121,20 @@ ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const {
       .str();
 }
 
+static unsigned nextAPIntBitWidth(unsigned BitWidth) {
+  return (BitWidth < APInt::APINT_BITS_PER_WORD) ? APInt::APINT_BITS_PER_WORD
+                                                 : BitWidth * 2;
+}
+
+static APInt toSigned(APInt AbsVal, bool Negative) {
+  if (AbsVal.isSignBitSet())
+    AbsVal = AbsVal.zext(nextAPIntBitWidth(AbsVal.getBitWidth()));
+  APInt Result = AbsVal;
+  if (Negative)
+    Result.negate();
+  return Result;
+}
+
 Expected<ExpressionValue>
 ExpressionFormat::valueFromStringRepr(StringRef StrVal,
                                       const SourceMgr &SM) const {
@@ -138,101 +144,70 @@ ExpressionFormat::valueFromStringRepr(StringRef StrVal,
   // getWildcardRegex() above. Only underflow and overflow errors can thus
   // occur. However new uses of this method could be added in the future so
   // the error message does not make assumptions about StrVal.
-  StringRef IntegerParseErrorStr = "unable to represent numeric value";
-  if (ValueIsSigned) {
-    int64_t SignedValue;
-
-    if (StrVal.getAsInteger(10, SignedValue))
-      return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr);
-
-    return ExpressionValue(SignedValue);
-  }
-
+  bool Negative = StrVal.consume_front("-");
   bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower;
-  uint64_t UnsignedValue;
-  bool MissingFormPrefix = AlternateForm && !StrVal.consume_front("0x");
+  bool MissingFormPrefix =
+      !ValueIsSigned && AlternateForm && !StrVal.consume_front("0x");
   (void)MissingFormPrefix;
   assert(!MissingFormPrefix && "missing alternate form prefix");
-  if (StrVal.getAsInteger(Hex ? 16 : 10, UnsignedValue))
-    return ErrorDiagnostic::get(SM, StrVal, IntegerParseErrorStr);
-
-  return ExpressionValue(UnsignedValue);
+  APInt ResultValue;
+  bool ParseFailure = StrVal.getAsInteger(Hex ? 16 : 10, ResultValue);
+  if (ParseFailure)
+    return ErrorDiagnostic::get(SM, StrVal,
+                                "unable to represent numeric value");
+  return ExpressionValue(toSigned(ResultValue, Negative));
 }
 
-Expected<ExpressionValue> llvm::operator+(const ExpressionValue &LeftOperand,
-                                          const ExpressionValue &RightOperand) {
-  bool Overflow;
+Expected<ExpressionValue> llvm::exprAdd(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
   APInt Result = LeftOperand.getAPIntValue().sadd_ov(
       RightOperand.getAPIntValue(), Overflow);
-  if (Overflow ||
-      (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1)))
-    return make_error<OverflowError>();
-
-  if (Result.isNegative())
-    return ExpressionValue(Result.getSExtValue());
-  else
-    return ExpressionValue(Result.getZExtValue());
+  return ExpressionValue(Result);
 }
 
-Expected<ExpressionValue> llvm::operator-(const ExpressionValue &LeftOperand,
-                                          const ExpressionValue &RightOperand) {
-  bool Overflow;
+Expected<ExpressionValue> llvm::exprSub(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
   APInt Result = LeftOperand.getAPIntValue().ssub_ov(
       RightOperand.getAPIntValue(), Overflow);
-  if (Overflow ||
-      (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1)))
-    return make_error<OverflowError>();
-
-  if (Result.isNegative())
-    return ExpressionValue(Result.getSExtValue());
-  else
-    return ExpressionValue(Result.getZExtValue());
+  return ExpressionValue(Result);
 }
 
-Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand,
-                                          const ExpressionValue &RightOperand) {
-  bool Overflow;
+Expected<ExpressionValue> llvm::exprMul(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
   APInt Result = LeftOperand.getAPIntValue().smul_ov(
       RightOperand.getAPIntValue(), Overflow);
-  if (Overflow ||
-      (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1)))
-    return make_error<OverflowError>();
-
-  if (Result.isNegative())
-    return ExpressionValue(Result.getSExtValue());
-  else
-    return ExpressionValue(Result.getZExtValue());
+  return ExpressionValue(Result);
 }
 
-Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand,
-                                          const ExpressionValue &RightOperand) {
+Expected<ExpressionValue> llvm::exprDiv(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
   // Check for division by zero.
   if (RightOperand.getAPIntValue().isZero())
     return make_error<OverflowError>();
 
-  bool Overflow;
   APInt Result = LeftOperand.getAPIntValue().sdiv_ov(
       RightOperand.getAPIntValue(), Overflow);
-  if (Overflow ||
-      (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1)))
-    return make_error<OverflowError>();
-
-  if (Result.isNegative())
-    return ExpressionValue(Result.getSExtValue());
-  else
-    return ExpressionValue(Result.getZExtValue());
+  return ExpressionValue(Result);
 }
 
-Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand,
-                                    const ExpressionValue &RightOperand) {
+Expected<ExpressionValue> llvm::exprMax(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
+  Overflow = false;
   return LeftOperand.getAPIntValue().slt(RightOperand.getAPIntValue())
              ? RightOperand
              : LeftOperand;
 }
 
-Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand,
-                                    const ExpressionValue &RightOperand) {
-  if (cantFail(max(LeftOperand, RightOperand)).getAPIntValue() ==
+Expected<ExpressionValue> llvm::exprMin(const ExpressionValue &LeftOperand,
+                                        const ExpressionValue &RightOperand,
+                                        bool &Overflow) {
+  Overflow = false;
+  if (cantFail(exprMax(LeftOperand, RightOperand, Overflow)).getAPIntValue() ==
       LeftOperand.getAPIntValue())
     return RightOperand;
 
@@ -248,21 +223,42 @@ Expected<ExpressionValue> NumericVariableUse::eval() const {
 }
 
 Expected<ExpressionValue> BinaryOperation::eval() const {
-  Expected<ExpressionValue> LeftOp = LeftOperand->eval();
-  Expected<ExpressionValue> RightOp = RightOperand->eval();
+  Expected<ExpressionValue> MaybeLeftOp = LeftOperand->eval();
+  Expected<ExpressionValue> MaybeRightOp = RightOperand->eval();
 
   // Bubble up any error (e.g. undefined variables) in the recursive
   // evaluation.
-  if (!LeftOp || !RightOp) {
+  if (!MaybeLeftOp || !MaybeRightOp) {
     Error Err = Error::success();
-    if (!LeftOp)
-      Err = joinErrors(std::move(Err), LeftOp.takeError());
-    if (!RightOp)
-      Err = joinErrors(std::move(Err), RightOp.takeError());
+    if (!MaybeLeftOp)
+      Err = joinErrors(std::move(Err), MaybeLeftOp.takeError());
+    if (!MaybeRightOp)
+      Err = joinErrors(std::move(Err), MaybeRightOp.takeError());
     return std::move(Err);
   }
 
-  return EvalBinop(*LeftOp, *RightOp);
+  APInt LeftOp = MaybeLeftOp->getAPIntValue();
+  APInt RightOp = MaybeRightOp->getAPIntValue();
+  bool Overflow;
+  // Ensure both operands have the same bitwidth.
+  unsigned LeftBitWidth = LeftOp.getBitWidth();
+  unsigned RightBitWidth = RightOp.getBitWidth();
+  unsigned NewBitWidth = std::max(LeftBitWidth, RightBitWidth);
+  LeftOp = LeftOp.sext(NewBitWidth);
+  RightOp = RightOp.sext(NewBitWidth);
+  do {
+    Expected<ExpressionValue> MaybeResult =
+        EvalBinop(ExpressionValue(LeftOp), ExpressionValue(RightOp), Overflow);
+    if (!MaybeResult)
+      return MaybeResult.takeError();
+
+    if (!Overflow)
+      return MaybeResult;
+
+    NewBitWidth = nextAPIntBitWidth(NewBitWidth);
+    LeftOp = LeftOp.sext(NewBitWidth);
+    RightOp = RightOp.sext(NewBitWidth);
+  } while (true);
 }
 
 Expected<ExpressionFormat>
@@ -466,21 +462,17 @@ Expected<std::unique_ptr<ExpressionAST>> Pattern::parseNumericOperand(
   }
 
   // Otherwise, parse it as a literal.
-  int64_t SignedLiteralValue;
-  uint64_t UnsignedLiteralValue;
+  APInt LiteralValue;
   StringRef SaveExpr = Expr;
-  // Accept both signed and unsigned literal, default to signed literal.
+  bool Negative = Expr.consume_front("-");
   if (!Expr.consumeInteger((AO == AllowedOperand::LegacyLiteral) ? 10 : 0,
-                           UnsignedLiteralValue))
+                           LiteralValue)) {
+    LiteralValue = toSigned(LiteralValue, Negative);
     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);
-
+                                               LiteralValue);
+  }
   return ErrorDiagnostic::get(
-      SM, Expr,
+      SM, SaveExpr,
       Twine("invalid ") +
           (MaybeInvalidConstraint ? "matching constraint or " : "") +
           "operand format");
@@ -535,10 +527,10 @@ Pattern::parseBinop(StringRef Expr, StringRef &RemainingExpr,
   binop_eval_t EvalBinop;
   switch (Operator) {
   case '+':
-    EvalBinop = operator+;
+    EvalBinop = exprAdd;
     break;
   case '-':
-    EvalBinop = operator-;
+    EvalBinop = exprSub;
     break;
   default:
     return ErrorDiagnostic::get(
@@ -572,12 +564,12 @@ Pattern::parseCallExpr(StringRef &Expr, StringRef FuncName,
   assert(Expr.startswith("("));
 
   auto OptFunc = StringSwitch<binop_eval_t>(FuncName)
-                     .Case("add", operator+)
-                     .Case("div", operator/)
-                     .Case("max", max)
-                     .Case("min", min)
-                     .Case("mul", operator*)
-                     .Case("sub", operator-)
+                     .Case("add", exprAdd)
+                     .Case("div", exprDiv)
+                     .Case("max", exprMax)
+                     .Case("min", exprMin)
+                     .Case("mul", exprMul)
+                     .Case("sub", exprSub)
                      .Default(nullptr);
 
   if (!OptFunc)
@@ -1124,7 +1116,8 @@ Pattern::MatchResult Pattern::match(StringRef Buffer,
   if (!Substitutions.empty()) {
     TmpStr = RegExStr;
     if (LineNumber)
-      Context->LineVariable->setValue(ExpressionValue(*LineNumber));
+      Context->LineVariable->setValue(
+          ExpressionValue(APInt(sizeof(*LineNumber) * 8, *LineNumber)));
 
     size_t InsertOffset = 0;
     // Substitute all string variables and expressions whose values are only

diff  --git a/llvm/lib/FileCheck/FileCheckImpl.h b/llvm/lib/FileCheck/FileCheckImpl.h
index 10fe8d46ffac386..ff87a1eea40b932 100644
--- a/llvm/lib/FileCheck/FileCheckImpl.h
+++ b/llvm/lib/FileCheck/FileCheckImpl.h
@@ -124,27 +124,25 @@ class ExpressionValue {
   APInt Value;
 
 public:
-  // Store signed and unsigned 64-bit integers in a signed 65-bit APInt.
-  template <class T>
-  explicit ExpressionValue(T Val) : Value(65, Val, /*isSigned=*/Val < 0) {}
+  ExpressionValue(APInt Val) : Value(Val) {}
 
   APInt getAPIntValue() const { return Value; }
 };
 
 /// 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);
-Expected<ExpressionValue> operator*(const ExpressionValue &Lhs,
-                                    const ExpressionValue &Rhs);
-Expected<ExpressionValue> operator/(const ExpressionValue &Lhs,
-                                    const ExpressionValue &Rhs);
-Expected<ExpressionValue> max(const ExpressionValue &Lhs,
-                              const ExpressionValue &Rhs);
-Expected<ExpressionValue> min(const ExpressionValue &Lhs,
-                              const ExpressionValue &Rhs);
+Expected<ExpressionValue> exprAdd(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
+Expected<ExpressionValue> exprSub(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
+Expected<ExpressionValue> exprMul(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
+Expected<ExpressionValue> exprDiv(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
+Expected<ExpressionValue> exprMax(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
+Expected<ExpressionValue> exprMin(const ExpressionValue &Lhs,
+                                  const ExpressionValue &Rhs, bool &Overflow);
 
 /// Base class representing the AST of a given expression.
 class ExpressionAST {
@@ -179,8 +177,7 @@ class ExpressionLiteral : public ExpressionAST {
   ExpressionValue Value;
 
 public:
-  template <class T>
-  explicit ExpressionLiteral(StringRef ExpressionStr, T Val)
+  explicit ExpressionLiteral(StringRef ExpressionStr, APInt Val)
       : ExpressionAST(ExpressionStr), Value(Val) {}
 
   /// \returns the literal's value.
@@ -322,7 +319,8 @@ class NumericVariableUse : public ExpressionAST {
 
 /// Type of functions evaluating a given binary operation.
 using binop_eval_t = Expected<ExpressionValue> (*)(const ExpressionValue &,
-                                                   const ExpressionValue &);
+                                                   const ExpressionValue &,
+                                                   bool &);
 
 /// Class representing a single binary operation in the AST of an expression.
 class BinaryOperation : public ExpressionAST {

diff  --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
deleted file mode 100644
index a40597d90d053b2..000000000000000
--- a/llvm/test/FileCheck/match-time-error-propagation/invalid-excluded-pattern.txt
+++ /dev/null
@@ -1,67 +0,0 @@
-; Check handling of match-time diagnostics for invalid patterns (e.g.,
-; substitution overflow) in the case of excluded patterns (e.g., CHECK-NOT).
-;
-; At one time, FileCheck's exit status was zero for this case.  Moreover, it
-; printed the error diagnostic only if -vv was specified and input dumps were
-; disabled.  Test every combination as the logic is hard to get right.
-
-RUN: echo > %t.chk \
-RUN:      'CHECK-NOT: [[#0x8000000000000000+0x8000000000000000]] [[UNDEFVAR]]'
-RUN: echo > %t.in '10000000000000000'
-
-     ERR-NOT:{{.}}
-      ERR-VV:{{.*}}: remark: implicit EOF: expected string found in input
- ERR-VV-NEXT:CHECK-NOT: {{.*}}
- ERR-VV-NEXT:{{ *}}^
- ERR-VV-NEXT:{{.*}}: note: found here
-ERR-VV-EMPTY:
- ERR-VV-NEXT:^
-     ERR-NOT:{{.}}
-         ERR:{{.*}}: error: unable to substitute variable or numeric expression: overflow error
-    ERR-NEXT:CHECK-NOT: {{.*}}
-    ERR-NEXT:{{ *}}^
-    ERR-NEXT:{{.*}}: error: undefined variable: UNDEFVAR
-    ERR-NEXT:{{CHECK-NOT: \[\[#0x8000000000000000\+0x8000000000000000\]\] \[\[UNDEFVAR\]\]}}
-    ERR-NEXT:^
-     ERR-NOT:{{error|note|remark}}:
-
-        DUMP:<<<<<<
-   DUMP-NEXT:         1: 10000000000000000 
-   DUMP-NEXT:not:1'0     X~~~~~~~~~~~~~~~~~ error: match failed for invalid pattern
-   DUMP-NEXT:not:1'1                        unable to substitute variable or numeric expression: overflow error
-   DUMP-NEXT:not:1'2                        undefined variable: UNDEFVAR
-DUMP-VV-NEXT:         2: 
-DUMP-VV-NEXT:eof:1       ^
-   DUMP-NEXT:>>>>>>
-
-;--------------------------------------------------
-; Check -dump-input=never cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV
-
-;--------------------------------------------------
-; Check -dump-input=fail cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV

diff  --git a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
deleted file mode 100644
index 577f018e4782f7b..000000000000000
--- a/llvm/test/FileCheck/match-time-error-propagation/invalid-expected-pattern.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-; Check handling of match-time diagnostics for invalid patterns (e.g.,
-; substitution overflow) in the case of expected patterns (e.g., CHECK).
-
-RUN: echo > %t.chk \
-RUN:      'CHECK: [[#0x8000000000000000+0x8000000000000000]] [[UNDEFVAR]]'
-RUN: echo > %t.in '10000000000000000'
-
-  ERR-NOT:{{.}}
-      ERR:{{.*}}: error: unable to substitute variable or numeric expression: overflow error
- ERR-NEXT:CHECK: {{.*}}
- ERR-NEXT:{{ *}}^
- ERR-NEXT:{{.*}}: error: undefined variable: UNDEFVAR
- ERR-NEXT:{{CHECK: \[\[#0x8000000000000000\+0x8000000000000000\]\] \[\[UNDEFVAR\]\]}}
- ERR-NEXT:^
-  ERR-NOT:{{error|note|remark}}:
-
-     DUMP:<<<<<<
-DUMP-NEXT:           1: 10000000000000000 
-DUMP-NEXT:check:1'0     X~~~~~~~~~~~~~~~~~ error: match failed for invalid pattern
-DUMP-NEXT:check:1'1                        unable to substitute variable or numeric expression: overflow error
-DUMP-NEXT:check:1'2                        undefined variable: UNDEFVAR
-DUMP-NEXT:>>>>>>
-
-;--------------------------------------------------
-; Check -dump-input=never cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-;--------------------------------------------------
-; Check -dump-input=fail cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP

diff  --git a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
deleted file mode 100644
index 32ffbf2e8f211e1..000000000000000
--- a/llvm/test/FileCheck/match-time-error-propagation/matched-excluded-pattern.txt
+++ /dev/null
@@ -1,88 +0,0 @@
-; Check handling of diagnostics for problematic matches (e.g., variable capture
-; overflow) in the case of excluded patterns (e.g., CHECK-NOT).
-;
-; At one time, FileCheck's exit status for the following example was zero even
-; though the excluded pattern does match (it's just capturing that fails).
-; Moreover, it printed the error diagnostic only if -vv was specified and input
-; dumps were disabled.  Test every combination as the logic is hard to get
-; right. 
-;
-; TODO: Capturing from an excluded pattern probably shouldn't be permitted
-; because it seems useless: it's captured only if the pattern matches, but then
-; FileCheck fails.  The helpfulness of reporting overflow from that capture is
-; perhaps questionable then, but it doesn't seem harmful either.  Anyway, the
-; goal of this test is simply to exercise the error propagation mechanism for a
-; matched excluded pattern.  In the future, if we have a more interesting error
-; to exercise in that case, we should instead use it in this test, and then we
-; might want to think more about where that error should be presented in the
-; list of diagnostics.
-
-RUN: echo > %t.chk 'CHECK-NOT: [[#122+1]] [[STR:abc]] [[#NUM:]]'
-RUN: echo > %t.in '123 abc 1000000000000000000000000000000000000000000000000000'
-
-     ERR-NOT:{{.}}
-      ERR-VV:{{.*}}: remark: implicit EOF: expected string found in input
- ERR-VV-NEXT:CHECK-NOT: {{.*}}
- ERR-VV-NEXT:{{ *}}^
- ERR-VV-NEXT:{{.*}}: note: found here
-ERR-VV-EMPTY:
- ERR-VV-NEXT:^
-     ERR-NOT:{{.}}
-         ERR:{{.*}}: error: CHECK-NOT: excluded string found in input
-    ERR-NEXT:CHECK-NOT: {{.*}}
-    ERR-NEXT:{{ *}}^
-    ERR-NEXT:<stdin>:1:1: note: found here
-    ERR-NEXT:123 abc 10{{0*}}
-    ERR-NEXT:^~~~~~~~~{{~*}}
-    ERR-NEXT:<stdin>:1:1: note: with "122+1" equal to "123"
-    ERR-NEXT:123 abc 10{{0*}}
-    ERR-NEXT:^
-    ERR-NEXT:<stdin>:1:5: note: captured var "STR"
-    ERR-NEXT:123 abc 10{{0*}}
-    ERR-NEXT:    ^~~
-    ERR-NEXT:<stdin>:1:9: error: unable to represent numeric value
-    ERR-NEXT:123 abc 10{{0*}}
-    ERR-NEXT:        ^
-     ERR-NOT:{{error|note|remark}}:
-
-        DUMP:<<<<<<
-   DUMP-NEXT:         1: 123 abc 10{{0*}} 
-   DUMP-NEXT:not:1'0     !~~~~~~~~~{{~*}}  error: no match expected
-   DUMP-NEXT:not:1'1                       with "122+1" equal to "123"
-   DUMP-NEXT:not:1'2         !~~           captured var "STR"
-   DUMP-NEXT:not:1'3             !~{{~*}}  error: unable to represent numeric value
-DUMP-VV-NEXT:         2: 
-DUMP-VV-NEXT:eof:1       ^
-   DUMP-NEXT:>>>>>>
-
-;--------------------------------------------------
-; Check -dump-input=never cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,ERR-VV
-
-;--------------------------------------------------
-; Check -dump-input=fail cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP,DUMP-VV

diff  --git a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt b/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt
deleted file mode 100644
index d376f73bfdc0f3f..000000000000000
--- a/llvm/test/FileCheck/match-time-error-propagation/matched-expected-pattern.txt
+++ /dev/null
@@ -1,63 +0,0 @@
-; Check handling of diagnostics for problematic matches (e.g., variable capture
-; overflow) in the case of expected patterns (e.g., CHECK).
-
-RUN: echo > %t.chk 'CHECK: [[#122+1]] [[STR:abc]] [[#NUM:]]'
-RUN: echo > %t.in '123 abc 1000000000000000000000000000000000000000000000000000'
-
-  ERR-NOT:{{.}}
-      ERR:{{.*}}: remark: CHECK: expected string found in input
- ERR-NEXT:CHECK: {{.*}}
- ERR-NEXT:{{ *}}^
- ERR-NEXT:<stdin>:1:1: note: found here
- ERR-NEXT:123 abc 10{{0*}}
- ERR-NEXT:^~~~~~~~~{{~*}}
- ERR-NEXT:<stdin>:1:1: note: with "122+1" equal to "123"
- ERR-NEXT:123 abc 10{{0*}}
- ERR-NEXT:^
- ERR-NEXT:<stdin>:1:5: note: captured var "STR"
- ERR-NEXT:123 abc 10{{0*}}
- ERR-NEXT:    ^~~
- ERR-NEXT:<stdin>:1:9: error: unable to represent numeric value
- ERR-NEXT:123 abc 10{{0*}}
- ERR-NEXT:        ^
-  ERR-NOT:{{error|note|remark}}:
-
-     DUMP:<<<<<<
-DUMP-NEXT:           1: 123 abc 10{{0*}} 
-DUMP-NEXT:check:1'0     ^~~~~~~~~~{{~*}}
-DUMP-NEXT:check:1'1                       with "122+1" equal to "123"
-DUMP-NEXT:check:1'2         ^~~           captured var "STR"
-DUMP-NEXT:check:1'3             !~{{~*}}  error: unable to represent numeric value
-DUMP-NEXT:>>>>>>
-
-;--------------------------------------------------
-; Check -dump-input=never cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=never -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR
-
-;--------------------------------------------------
-; Check -dump-input=fail cases.
-;--------------------------------------------------
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -v %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP
-
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck -dump-input=fail -vv %t.chk < %t.in 2>&1 \
-RUN: | FileCheck %s -match-full-lines -check-prefixes=ERR,DUMP

diff  --git a/llvm/test/FileCheck/numeric-expression.txt b/llvm/test/FileCheck/numeric-expression.txt
index d76552651ef8a1f..1430484d08ebc7b 100644
--- a/llvm/test/FileCheck/numeric-expression.txt
+++ b/llvm/test/FileCheck/numeric-expression.txt
@@ -487,18 +487,13 @@ CLI-NUM-CONFLICT: Global defines:2:45: error: string variable with name 'STRVAR'
  CLI-NUM-CONFLICT-NEXT: Global define #2: #STRVAR=42 (parsed as: {{\[\[#STRVAR:42\]\]}})
 CLI-NUM-CONFLICT-NEXT: {{^}}                                            ^{{$}}
 
-; Numeric variable definition with too big value.
-RUN: %ProtectFileCheckOutput \
-RUN: not FileCheck --check-prefix BIGVAL --input-file %s %s 2>&1 \
-RUN:   | FileCheck --strict-whitespace --check-prefix BIGVAL-MSG %s
+; Numeric variable definition with big value.
+RUN: FileCheck --check-prefix BIGVAL --input-file %s %s
 
 BIG VALUE
 NUMVAR: 10000000000000000000000
 BIGVAL-LABEL: BIG VALUE
 BIGVAL-NEXT: NUMVAR: [[#NUMVAR:]]
-BIGVAL-MSG: numeric-expression.txt:[[#@LINE-3]]:9: error: unable to represent numeric value
- BIGVAL-MSG-NEXT: {{N}}UMVAR: 10000000000000000000000
-BIGVAL-MSG-NEXT: {{^}}        ^{{$}}
 
 ; Verify that when a variable is set to an expression the expression is still
 ; checked.
@@ -557,31 +552,21 @@ REDEF-NEW-FMT-MSG: numeric-expression.txt:[[#@LINE-1]]:31: error: format 
diff ere
 REDEF-NEW-FMT-MSG-NEXT: {{R}}EDEF-NEW-FMT-NEXT: {{\[\[#%X,UNSI:\]\]}}
 REDEF-NEW-FMT-MSG-NEXT:    {{^}}                              ^{{$}}
 
-; Numeric expression with overflow.
-RUN: %ProtectFileCheckOutput \
-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: %ProtectFileCheckOutput \
-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:    {{^}}                            ^{{$}}
+; Numeric expression with big resulting value.
+RUN: FileCheck --check-prefix OVERFLOW --input-file %s %s
+
+OVERFLOW EXPRESSION
+BIGVAL: 10000000000000000
+OVERFLOW-LABEL: OVERFLOW EXPRESSION
+OVERFLOW-NEXT: BIGVAL: [[#%X,0x8000000000000000+0x8000000000000000]]
+
+; Numeric expression with big negative resulting value.
+RUN: FileCheck --check-prefix UNDERFLOW --input-file %s %s
+
+UNDERFLOW EXPRESSION
+TINYVAR: -18446744073709551616 # -0x10000000000000000
+UNDERFLOW-LABEL: UNDERFLOW EXPRESSION
+UNDERFLOW-NEXT: TINYVAR: [[#%d,-0x8000000000000000-0x8000000000000000]]
 
 RUN: %ProtectFileCheckOutput \
 RUN: not FileCheck -D#NUMVAR=10 --check-prefix CALL-MISSING-CLOSING-BRACKET --input-file %s %s 2>&1 \

diff  --git a/llvm/unittests/FileCheck/FileCheckTest.cpp b/llvm/unittests/FileCheck/FileCheckTest.cpp
index 767de757800c9f7..eb7c4dab301f854 100644
--- a/llvm/unittests/FileCheck/FileCheckTest.cpp
+++ b/llvm/unittests/FileCheck/FileCheckTest.cpp
@@ -84,6 +84,9 @@ constexpr int64_t MinInt64 = std::numeric_limits<int64_t>::min();
 constexpr uint64_t AbsoluteMinInt64 =
     static_cast<uint64_t>(-(MinInt64 + 1)) + 1;
 constexpr uint64_t AbsoluteMaxInt64 = static_cast<uint64_t>(MaxInt64);
+// Use 128 bitwidth for literals to keep one bit for sign for uint64_t
+// literals.
+constexpr unsigned LiteralsBitWidth = 128;
 
 struct ExpressionFormatParameterisedFixture
     : public ::testing::TestWithParam<
@@ -184,16 +187,18 @@ struct ExpressionFormatParameterisedFixture
   }
 
   template <class T> void checkMatchingString(T Val, StringRef ExpectedStr) {
+    APInt Value(LiteralsBitWidth, Val, std::is_signed_v<T>);
     Expected<std::string> MatchingString =
-        Format.getMatchingString(ExpressionValue(Val));
+        Format.getMatchingString(ExpressionValue(Value));
     ASSERT_THAT_EXPECTED(MatchingString, Succeeded())
         << "No matching string for " << Val;
     EXPECT_EQ(*MatchingString, ExpectedStr);
   }
 
   template <class T> void checkMatchingStringFailure(T Val) {
+    APInt Value(LiteralsBitWidth, Val, std::is_signed_v<T>);
     Expected<std::string> MatchingString =
-        Format.getMatchingString(ExpressionValue(Val));
+        Format.getMatchingString(ExpressionValue(Value));
     // Error message tested in ExpressionValue unit tests.
     EXPECT_THAT_EXPECTED(MatchingString, Failed());
   }
@@ -286,7 +291,7 @@ TEST_P(ExpressionFormatParameterisedFixture, FormatGetMatchingString) {
 
   if (Signed) {
     checkMatchingString(-5, padWithLeadingZeros("-5"));
-    checkMatchingStringFailure(MaxUint64);
+    checkMatchingString(MaxUint64, padWithLeadingZeros(MaxUint64Str));
     checkMatchingString(MaxInt64, padWithLeadingZeros(MaxInt64Str));
     checkMatchingString(MinInt64, padWithLeadingZeros(MinInt64Str));
   } else {
@@ -308,7 +313,7 @@ TEST_P(ExpressionFormatParameterisedFixture, FormatValueFromStringRepr) {
 
   if (Signed) {
     checkValueFromStringRepr("-5", -5);
-    checkValueFromStringReprFailure(MaxUint64Str);
+    checkValueFromStringRepr(MaxUint64Str, MaxUint64);
   } else {
     checkValueFromStringRepr(addBasePrefix(MaxUint64Str), MaxUint64);
   }
@@ -358,7 +363,7 @@ TEST_F(FileCheckTest, NoFormatProperties) {
                            NoFormat.getWildcardRegex().takeError());
   expectError<StringError>(
       "trying to match value with invalid format",
-      NoFormat.getMatchingString(ExpressionValue(18u)).takeError());
+      NoFormat.getMatchingString(ExpressionValue(APInt(64, 18u))).takeError());
   EXPECT_FALSE(bool(NoFormat));
 }
 
@@ -389,172 +394,177 @@ 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) {
-  APInt Value = ActualValue.getAPIntValue();
-  EXPECT_EQ(ExpectedValue < 0, Value.isNegative());
-  if (ExpectedValue < 0)
-    EXPECT_EQ(Value.getSExtValue(), static_cast<int64_t>(ExpectedValue));
-  else
-    EXPECT_EQ(Value.getZExtValue(), static_cast<uint64_t>(ExpectedValue));
+static void expectOperationValueResult(binop_eval_t Operation, APInt LeftValue,
+                                       APInt RightValue, APInt ExpectedValue) {
+  bool Overflow;
+  ExpressionValue LeftVal(LeftValue);
+  ExpressionValue RightVal(RightValue);
+  Expected<ExpressionValue> OperationResult =
+      Operation(LeftVal, RightVal, Overflow);
+  ASSERT_THAT_EXPECTED(OperationResult, Succeeded());
+  EXPECT_EQ(OperationResult->getAPIntValue(), 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);
+  APInt LeftVal(LiteralsBitWidth, LeftValue, std::is_signed_v<T1>);
+  APInt RightVal(LiteralsBitWidth, RightValue, std::is_signed_v<T2>);
+  APInt ResultVal =
+      std::is_integral_v<TR>
+          ? APInt(LiteralsBitWidth, ResultValue, std::is_signed_v<TR>)
+          : APInt(LiteralsBitWidth, ResultValue, /*Radix=*/10);
+  expectOperationValueResult(Operation, LeftVal, RightVal, ResultVal);
 }
 
 template <class T1, class T2>
 static void expectOperationValueResult(binop_eval_t Operation, T1 LeftValue,
                                        T2 RightValue) {
+  bool Overflow;
+  ExpressionValue LeftVal(
+      APInt(LiteralsBitWidth, LeftValue, std::is_signed_v<T1>));
+  ExpressionValue RightVal(
+      APInt(LiteralsBitWidth, RightValue, std::is_signed_v<T2>));
   expectError<OverflowError>(
-      "overflow error",
-      doValueOperation(Operation, LeftValue, RightValue).takeError());
+      "overflow error", Operation(LeftVal, RightVal, Overflow).takeError());
 }
 
 TEST_F(FileCheckTest, ExpressionValueAddition) {
   // Test both negative values.
-  expectOperationValueResult(operator+, -10, -10, -20);
+  expectOperationValueResult(exprAdd, -10, -10, -20);
 
   // Test both negative values with underflow.
-  expectOperationValueResult(operator+, MinInt64, -1);
-  expectOperationValueResult(operator+, MinInt64, MinInt64);
+  expectOperationValueResult(exprAdd, MinInt64, -1, "-9223372036854775809");
+  expectOperationValueResult(exprAdd, MinInt64, MinInt64,
+                             "-18446744073709551616");
 
   // Test negative and positive value.
-  expectOperationValueResult(operator+, -10, 10, 0);
-  expectOperationValueResult(operator+, -10, 11, 1);
-  expectOperationValueResult(operator+, -11, 10, -1);
+  expectOperationValueResult(exprAdd, -10, 10, 0);
+  expectOperationValueResult(exprAdd, -10, 11, 1);
+  expectOperationValueResult(exprAdd, -11, 10, -1);
 
   // Test positive and negative value.
-  expectOperationValueResult(operator+, 10, -10, 0);
-  expectOperationValueResult(operator+, 10, -11, -1);
-  expectOperationValueResult(operator+, 11, -10, 1);
+  expectOperationValueResult(exprAdd, 10, -10, 0);
+  expectOperationValueResult(exprAdd, 10, -11, -1);
+  expectOperationValueResult(exprAdd, 11, -10, 1);
 
   // Test both positive values.
-  expectOperationValueResult(operator+, 10, 10, 20);
+  expectOperationValueResult(exprAdd, 10, 10, 20);
 
-  // Test both positive values with overflow.
-  expectOperationValueResult(operator+, MaxUint64, 1);
-  expectOperationValueResult(operator+, MaxUint64, MaxUint64);
+  // Test both positive values with result not representable as uint64_t.
+  expectOperationValueResult(exprAdd, MaxUint64, 1, "18446744073709551616");
+  expectOperationValueResult(exprAdd, MaxUint64, MaxUint64,
+                             "36893488147419103230");
 }
 
 TEST_F(FileCheckTest, ExpressionValueSubtraction) {
   // Test negative value and value bigger than int64_t max.
-  expectOperationValueResult(operator-, -10, MaxUint64);
+  expectOperationValueResult(exprSub, -10, MaxUint64, "-18446744073709551625");
 
-  // Test negative and positive value with underflow.
-  expectOperationValueResult(operator-, MinInt64, 1);
+  // Test negative and positive value with result not representable as int64_t.
+  expectOperationValueResult(exprSub, MinInt64, 1, "-9223372036854775809");
 
   // Test negative and positive value.
-  expectOperationValueResult(operator-, -10, 10, -20);
+  expectOperationValueResult(exprSub, -10, 10, -20);
 
   // Test both negative values.
-  expectOperationValueResult(operator-, -10, -10, 0);
-  expectOperationValueResult(operator-, -11, -10, -1);
-  expectOperationValueResult(operator-, -10, -11, 1);
+  expectOperationValueResult(exprSub, -10, -10, 0);
+  expectOperationValueResult(exprSub, -11, -10, -1);
+  expectOperationValueResult(exprSub, -10, -11, 1);
 
   // Test positive and negative values.
-  expectOperationValueResult(operator-, 10, -10, 20);
+  expectOperationValueResult(exprSub, 10, -10, 20);
 
   // Test both positive values with result positive.
-  expectOperationValueResult(operator-, 10, 5, 5);
+  expectOperationValueResult(exprSub, 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 not representable as int64_t.
+  expectOperationValueResult(exprSub, 0, MaxUint64, "-18446744073709551615");
+  expectOperationValueResult(exprSub, 0,
+                             static_cast<uint64_t>(-(MinInt64 + 10)) + 11,
+                             "-9223372036854775809");
 
   // Test both positive values with result < -(max int64_t)
-  expectOperationValueResult(operator-, 10,
-                             static_cast<uint64_t>(MaxInt64) + 11,
+  expectOperationValueResult(exprSub, 10, static_cast<uint64_t>(MaxInt64) + 11,
                              -MaxInt64 - 1);
 
   // Test both positive values with 0 > result > -(max int64_t)
-  expectOperationValueResult(operator-, 10, 11, -1);
+  expectOperationValueResult(exprSub, 10, 11, -1);
 }
 
 TEST_F(FileCheckTest, ExpressionValueMultiplication) {
   // Test mixed signed values.
-  expectOperationValueResult(operator*, -3, 10, -30);
-  expectOperationValueResult(operator*, 2, -17, -34);
-  expectOperationValueResult(operator*, 0, MinInt64, 0);
-  expectOperationValueResult(operator*, MinInt64, 1, MinInt64);
-  expectOperationValueResult(operator*, 1, MinInt64, MinInt64);
-  expectOperationValueResult(operator*, MaxInt64, -1, -MaxInt64);
-  expectOperationValueResult(operator*, -1, MaxInt64, -MaxInt64);
+  expectOperationValueResult(exprMul, -3, 10, -30);
+  expectOperationValueResult(exprMul, 2, -17, -34);
+  expectOperationValueResult(exprMul, 0, MinInt64, 0);
+  expectOperationValueResult(exprMul, MinInt64, 1, MinInt64);
+  expectOperationValueResult(exprMul, 1, MinInt64, MinInt64);
+  expectOperationValueResult(exprMul, MaxInt64, -1, -MaxInt64);
+  expectOperationValueResult(exprMul, -1, MaxInt64, -MaxInt64);
 
   // Test both negative values.
-  expectOperationValueResult(operator*, -3, -10, 30);
-  expectOperationValueResult(operator*, -2, -17, 34);
-  expectOperationValueResult(operator*, MinInt64, -1, AbsoluteMinInt64);
+  expectOperationValueResult(exprMul, -3, -10, 30);
+  expectOperationValueResult(exprMul, -2, -17, 34);
+  expectOperationValueResult(exprMul, MinInt64, -1, AbsoluteMinInt64);
 
   // Test both positive values.
-  expectOperationValueResult(operator*, 3, 10, 30);
-  expectOperationValueResult(operator*, 2, 17, 34);
-  expectOperationValueResult(operator*, 0, MaxUint64, 0);
-
-  // Test negative results that underflow.
-  expectOperationValueResult(operator*, -10, MaxInt64);
-  expectOperationValueResult(operator*, MaxInt64, -10);
-  expectOperationValueResult(operator*, 10, MinInt64);
-  expectOperationValueResult(operator*, MinInt64, 10);
-  expectOperationValueResult(operator*, -1, MaxUint64);
-  expectOperationValueResult(operator*, MaxUint64, -1);
-  expectOperationValueResult(operator*, -1, AbsoluteMaxInt64 + 2);
-  expectOperationValueResult(operator*, AbsoluteMaxInt64 + 2, -1);
-
-  // Test positive results that overflow.
-  expectOperationValueResult(operator*, 10, MaxUint64);
-  expectOperationValueResult(operator*, MaxUint64, 10);
-  expectOperationValueResult(operator*, MinInt64, -10);
-  expectOperationValueResult(operator*, -10, MinInt64);
+  expectOperationValueResult(exprMul, 3, 10, 30);
+  expectOperationValueResult(exprMul, 2, 17, 34);
+  expectOperationValueResult(exprMul, 0, MaxUint64, 0);
+
+  // Test negative results not representable as int64_t.
+  expectOperationValueResult(exprMul, -10, MaxInt64, "-92233720368547758070");
+  expectOperationValueResult(exprMul, MaxInt64, -10, "-92233720368547758070");
+  expectOperationValueResult(exprMul, 10, MinInt64, "-92233720368547758080");
+  expectOperationValueResult(exprMul, MinInt64, 10, "-92233720368547758080");
+  expectOperationValueResult(exprMul, -1, MaxUint64, "-18446744073709551615");
+  expectOperationValueResult(exprMul, MaxUint64, -1, "-18446744073709551615");
+  expectOperationValueResult(exprMul, -1, AbsoluteMaxInt64 + 2,
+                             "-9223372036854775809");
+  expectOperationValueResult(exprMul, AbsoluteMaxInt64 + 2, -1,
+                             "-9223372036854775809");
+
+  // Test positive results not representable as uint64_t.
+  expectOperationValueResult(exprMul, 10, MaxUint64, "184467440737095516150");
+  expectOperationValueResult(exprMul, MaxUint64, 10, "184467440737095516150");
+  expectOperationValueResult(exprMul, MinInt64, -10, "92233720368547758080");
+  expectOperationValueResult(exprMul, -10, MinInt64, "92233720368547758080");
 }
 
 TEST_F(FileCheckTest, ExpressionValueDivision) {
   // Test mixed signed values.
-  expectOperationValueResult(operator/, -30, 10, -3);
-  expectOperationValueResult(operator/, 34, -17, -2);
-  expectOperationValueResult(operator/, 0, -10, 0);
-  expectOperationValueResult(operator/, MinInt64, 1, MinInt64);
-  expectOperationValueResult(operator/, MaxInt64, -1, -MaxInt64);
-  expectOperationValueResult(operator/, -MaxInt64, 1, -MaxInt64);
+  expectOperationValueResult(exprDiv, -30, 10, -3);
+  expectOperationValueResult(exprDiv, 34, -17, -2);
+  expectOperationValueResult(exprDiv, 0, -10, 0);
+  expectOperationValueResult(exprDiv, MinInt64, 1, MinInt64);
+  expectOperationValueResult(exprDiv, MaxInt64, -1, -MaxInt64);
+  expectOperationValueResult(exprDiv, -MaxInt64, 1, -MaxInt64);
 
   // Test both negative values.
-  expectOperationValueResult(operator/, -30, -10, 3);
-  expectOperationValueResult(operator/, -34, -17, 2);
+  expectOperationValueResult(exprDiv, -30, -10, 3);
+  expectOperationValueResult(exprDiv, -34, -17, 2);
 
   // Test both positive values.
-  expectOperationValueResult(operator/, 30, 10, 3);
-  expectOperationValueResult(operator/, 34, 17, 2);
-  expectOperationValueResult(operator/, 0, 10, 0);
+  expectOperationValueResult(exprDiv, 30, 10, 3);
+  expectOperationValueResult(exprDiv, 34, 17, 2);
+  expectOperationValueResult(exprDiv, 0, 10, 0);
 
   // Test divide by zero.
-  expectOperationValueResult(operator/, -10, 0);
-  expectOperationValueResult(operator/, 10, 0);
-  expectOperationValueResult(operator/, 0, 0);
-
-  // Test negative result that underflows.
-  expectOperationValueResult(operator/, MaxUint64, -1);
-  expectOperationValueResult(operator/, AbsoluteMaxInt64 + 2, -1);
+  expectOperationValueResult(exprDiv, -10, 0);
+  expectOperationValueResult(exprDiv, 10, 0);
+  expectOperationValueResult(exprDiv, 0, 0);
+
+  // Test negative result not representable as int64_t.
+  expectOperationValueResult(exprDiv, MaxUint64, -1, "-18446744073709551615");
+  expectOperationValueResult(exprDiv, AbsoluteMaxInt64 + 2, -1,
+                             "-9223372036854775809");
 }
 
 TEST_F(FileCheckTest, Literal) {
   SourceMgr SM;
 
   // Eval returns the literal's value.
-  ExpressionLiteral Ten(bufferize(SM, "10"), 10u);
+  ExpressionLiteral Ten(bufferize(SM, "10"), APInt(64, 10u));
   Expected<ExpressionValue> Value = Ten.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
   EXPECT_EQ(10, Value->getAPIntValue().getSExtValue());
@@ -563,13 +573,15 @@ TEST_F(FileCheckTest, Literal) {
   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::NoFormat);
 
   // Min value can be correctly represented.
-  ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)), MinInt64);
+  ExpressionLiteral Min(bufferize(SM, std::to_string(MinInt64)),
+                        APInt(64, MinInt64, /*IsSigned=*/true));
   Value = Min.eval();
   ASSERT_TRUE(bool(Value));
   EXPECT_EQ(MinInt64, Value->getAPIntValue().getSExtValue());
 
   // Max value can be correctly represented.
-  ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)), MaxUint64);
+  ExpressionLiteral Max(bufferize(SM, std::to_string(MaxUint64)),
+                        APInt(64, MaxUint64));
   Value = Max.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
   EXPECT_EQ(MaxUint64, Value->getAPIntValue().getZExtValue());
@@ -579,7 +591,7 @@ TEST_F(FileCheckTest, Expression) {
   SourceMgr SM;
 
   std::unique_ptr<ExpressionLiteral> Ten =
-      std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), 10u);
+      std::make_unique<ExpressionLiteral>(bufferize(SM, "10"), APInt(64, 10u));
   ExpressionLiteral *TenPtr = Ten.get();
   Expression Expr(std::move(Ten),
                   ExpressionFormat(ExpressionFormat::Kind::HexLower));
@@ -618,7 +630,7 @@ TEST_F(FileCheckTest, NumericVariable) {
   expectUndefErrors({"FOO"}, EvalResult.takeError());
 
   // Defined variable without string: only getValue and eval return value set.
-  FooVar.setValue(ExpressionValue(42u));
+  FooVar.setValue(ExpressionValue(APInt(64, 42u)));
   std::optional<ExpressionValue> Value = FooVar.getValue();
   ASSERT_TRUE(Value);
   EXPECT_EQ(42, Value->getAPIntValue().getSExtValue());
@@ -630,7 +642,7 @@ TEST_F(FileCheckTest, NumericVariable) {
   // Defined variable with string: getValue, eval, and getStringValue return
   // value set.
   StringRef StringValue = "925";
-  FooVar.setValue(ExpressionValue(925u), StringValue);
+  FooVar.setValue(ExpressionValue(APInt(64, 925u)), StringValue);
   Value = FooVar.getValue();
   ASSERT_TRUE(Value);
   EXPECT_EQ(925, Value->getAPIntValue().getSExtValue());
@@ -658,21 +670,20 @@ TEST_F(FileCheckTest, Binop) {
   StringRef FooStr = ExprStr.take_front(3);
   NumericVariable FooVar(FooStr,
                          ExpressionFormat(ExpressionFormat::Kind::Unsigned), 1);
-  FooVar.setValue(ExpressionValue(42u));
+  FooVar.setValue(ExpressionValue(APInt(64, 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(ExpressionValue(18u));
+  BarVar.setValue(ExpressionValue(APInt(64, 18u)));
   std::unique_ptr<NumericVariableUse> BarVarUse =
       std::make_unique<NumericVariableUse>(BarStr, &BarVar);
-  binop_eval_t doAdd = operator+;
-  BinaryOperation Binop(ExprStr, doAdd, std::move(FooVarUse),
+  BinaryOperation Binop(ExprStr, exprAdd, std::move(FooVarUse),
                         std::move(BarVarUse));
 
-  // Defined variables: eval returns right value; implicit format is as
-  // expected.
+  // Defined variables with same bitwidth and no overflow: eval returns right
+  // value; implicit formas is as expected.
   Expected<ExpressionValue> Value = Binop.eval();
   ASSERT_THAT_EXPECTED(Value, Succeeded());
   EXPECT_EQ(60, Value->getAPIntValue().getSExtValue());
@@ -680,6 +691,23 @@ TEST_F(FileCheckTest, Binop) {
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
   EXPECT_EQ(*ImplicitFormat, ExpressionFormat::Kind::Unsigned);
 
+  // Defined variables with 
diff erent bitwidth and no overflow: eval succeeds
+  // and return the right value.
+  BarVar.setValue(ExpressionValue(APInt(32, 18u)));
+  Value = Binop.eval();
+  ASSERT_THAT_EXPECTED(Value, Succeeded());
+  EXPECT_EQ(60, Value->getAPIntValue().getSExtValue());
+
+  // Defined variables with same bitwidth and wider result (i.e. overflow):
+  // eval succeeds and return the right value in a wider APInt.
+  BarVar.setValue(ExpressionValue(APInt(64, AbsoluteMaxInt64)));
+  Value = Binop.eval();
+  ASSERT_THAT_EXPECTED(Value, Succeeded());
+  EXPECT_EQ(128u, Value->getAPIntValue().getBitWidth());
+  EXPECT_EQ(APInt(128, AbsoluteMaxInt64 +
+                           FooVar.getValue()->getAPIntValue().getZExtValue()),
+            Value->getAPIntValue());
+
   // 1 undefined variable: eval fails, error contains name of undefined
   // variable.
   FooVar.clearValue();
@@ -698,8 +726,8 @@ 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, 18u);
-  Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse),
+      std::make_unique<ExpressionLiteral>(EighteenStr, APInt(64, 18u));
+  Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse),
                           std::move(Eighteen));
   ImplicitFormat = Binop.getImplicitFormat(SM);
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
@@ -708,8 +736,8 @@ 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, 18u);
-  Binop = BinaryOperation(ExprStr, doAdd, std::move(Eighteen),
+  Eighteen = std::make_unique<ExpressionLiteral>(EighteenStr, APInt(64, 18u));
+  Binop = BinaryOperation(ExprStr, exprAdd, std::move(Eighteen),
                           std::move(FooVarUse));
   ImplicitFormat = Binop.getImplicitFormat(SM);
   ASSERT_THAT_EXPECTED(ImplicitFormat, Succeeded());
@@ -724,7 +752,7 @@ TEST_F(FileCheckTest, Binop) {
   FooVarUse = std::make_unique<NumericVariableUse>(FooStr, &FooVar);
   std::unique_ptr<NumericVariableUse> BazVarUse =
       std::make_unique<NumericVariableUse>(BazStr, &BazVar);
-  Binop = BinaryOperation(ExprStr, doAdd, std::move(FooVarUse),
+  Binop = BinaryOperation(ExprStr, exprAdd, std::move(FooVarUse),
                           std::move(BazVarUse));
   ImplicitFormat = Binop.getImplicitFormat(SM);
   expectDiagnosticError(
@@ -749,12 +777,13 @@ TEST_F(FileCheckTest, Binop) {
   std::unique_ptr<NumericVariableUse> QuuxVarUse =
       std::make_unique<NumericVariableUse>(QuuxStr, &QuuxVar);
   std::unique_ptr<BinaryOperation> Binop1 = std::make_unique<BinaryOperation>(
-      ExprStr.take_front(9), doAdd, std::move(FooVarUse), std::move(BazVarUse));
+      ExprStr.take_front(9), exprAdd, std::move(FooVarUse),
+      std::move(BazVarUse));
   std::unique_ptr<BinaryOperation> Binop2 = std::make_unique<BinaryOperation>(
-      ExprStr.take_back(10), doAdd, std::move(FooVarUse2),
+      ExprStr.take_back(10), exprAdd, std::move(FooVarUse2),
       std::move(QuuxVarUse));
   std::unique_ptr<BinaryOperation> OuterBinop =
-      std::make_unique<BinaryOperation>(ExprStr, doAdd, std::move(Binop1),
+      std::make_unique<BinaryOperation>(ExprStr, exprAdd, std::move(Binop1),
                                         std::move(Binop2));
   ImplicitFormat = OuterBinop->getImplicitFormat(SM);
   expectSameErrors<ErrorDiagnostic>(
@@ -1434,7 +1463,7 @@ TEST_F(FileCheckTest, Substitution) {
   // substituted for the variable's value.
   NumericVariable NVar("N", ExpressionFormat(ExpressionFormat::Kind::Unsigned),
                        1);
-  NVar.setValue(ExpressionValue(10u));
+  NVar.setValue(ExpressionValue(APInt(64, 10u)));
   auto NVarUse = std::make_unique<NumericVariableUse>("N", &NVar);
   auto ExpressionN = std::make_unique<Expression>(
       std::move(NVarUse), ExpressionFormat(ExpressionFormat::Kind::HexUpper));


        


More information about the llvm-commits mailing list