diff options
Diffstat (limited to 'llvm/lib/FileCheck')
-rw-r--r-- | llvm/lib/FileCheck/FileCheck.cpp | 270 | ||||
-rw-r--r-- | llvm/lib/FileCheck/FileCheckImpl.h | 39 |
2 files changed, 80 insertions, 229 deletions
diff --git a/llvm/lib/FileCheck/FileCheck.cpp b/llvm/lib/FileCheck/FileCheck.cpp index ec963c2de45b..3e4514f2545b 100644 --- a/llvm/lib/FileCheck/FileCheck.cpp +++ b/llvm/lib/FileCheck/FileCheck.cpp @@ -16,6 +16,7 @@ #include "llvm/FileCheck/FileCheck.h" #include "FileCheckImpl.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/CheckedArithmetic.h" @@ -78,38 +79,42 @@ Expected<std::string> ExpressionFormat::getWildcardRegex() const { Expected<std::string> ExpressionFormat::getMatchingString(ExpressionValue IntegerValue) const { - uint64_t AbsoluteValue; - StringRef SignPrefix = IntegerValue.isNegative() ? "-" : ""; - + 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) { - Expected<int64_t> SignedValue = IntegerValue.getSignedValue(); - if (!SignedValue) - return SignedValue.takeError(); - if (*SignedValue < 0) - AbsoluteValue = cantFail(IntegerValue.getAbsolute().getUnsignedValue()); - else - AbsoluteValue = *SignedValue; + if (!IntValue.isSignedIntN(64)) + return make_error<OverflowError>(); } else { - Expected<uint64_t> UnsignedValue = IntegerValue.getUnsignedValue(); - if (!UnsignedValue) - return UnsignedValue.takeError(); - AbsoluteValue = *UnsignedValue; + if (!IntValue.isIntN(64)) + return make_error<OverflowError>(); } - std::string AbsoluteValueStr; + unsigned Radix; + bool UpperCase = false; + SmallString<8> AbsoluteValueStr; + StringRef SignPrefix = IntValue.isNegative() ? "-" : ""; switch (Value) { case Kind::Unsigned: case Kind::Signed: - AbsoluteValueStr = utostr(AbsoluteValue); + Radix = 10; break; case Kind::HexUpper: + UpperCase = true; + Radix = 16; + break; case Kind::HexLower: - AbsoluteValueStr = utohexstr(AbsoluteValue, Value == Kind::HexLower); + Radix = 16; + UpperCase = false; break; default: return createStringError(std::errc::invalid_argument, "trying to match value with invalid format"); } + IntValue.abs().toString(AbsoluteValueStr, Radix, /*Signed=*/false, + /*formatAsCLiteral=*/false, + /*UpperCase=*/UpperCase); StringRef AlternateFormPrefix = AlternateForm ? StringRef("0x") : StringRef(); @@ -146,217 +151,89 @@ ExpressionFormat::valueFromStringRepr(StringRef StrVal, bool Hex = Value == Kind::HexUpper || Value == Kind::HexLower; uint64_t UnsignedValue; bool MissingFormPrefix = 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); - // Error out for a missing prefix only now that we know we have an otherwise - // valid integer. For example, "-0x18" is reported above instead. - if (MissingFormPrefix) - return ErrorDiagnostic::get(SM, StrVal, "missing alternate form prefix"); - return ExpressionValue(UnsignedValue); } -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 > (uint64_t)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()); - std::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()); - std::optional<uint64_t> Result = - checkedAddUnsigned<uint64_t>(LeftValue, RightValue); - if (!Result) + bool Overflow; + APInt Result = LeftOperand.getAPIntValue().sadd_ov( + RightOperand.getAPIntValue(), Overflow); + if (Overflow || + (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) return make_error<OverflowError>(); - return ExpressionValue(*Result); + if (Result.isNegative()) + return ExpressionValue(Result.getSExtValue()); + else + return ExpressionValue(Result.getZExtValue()); } 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 > (uint64_t)std::numeric_limits<int64_t>::max()) - return make_error<OverflowError>(); - std::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); - } + bool Overflow; + APInt Result = LeftOperand.getAPIntValue().ssub_ov( + RightOperand.getAPIntValue(), Overflow); + if (Overflow || + (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) + return make_error<OverflowError>(); - return ExpressionValue(-static_cast<int64_t>(AbsoluteDifference)); - } + if (Result.isNegative()) + return ExpressionValue(Result.getSExtValue()); + else + return ExpressionValue(Result.getZExtValue()); } Expected<ExpressionValue> llvm::operator*(const ExpressionValue &LeftOperand, const ExpressionValue &RightOperand) { - // -A * -B == A * B - if (LeftOperand.isNegative() && RightOperand.isNegative()) - return LeftOperand.getAbsolute() * RightOperand.getAbsolute(); - - // A * -B == -B * A - if (RightOperand.isNegative()) - return RightOperand * LeftOperand; - - assert(!RightOperand.isNegative() && "Unexpected negative operand!"); - - // Result will be negative and can underflow. - if (LeftOperand.isNegative()) { - auto Result = LeftOperand.getAbsolute() * RightOperand.getAbsolute(); - if (!Result) - return Result; - - return ExpressionValue(0) - *Result; - } - - // Result will be positive and can overflow. - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - std::optional<uint64_t> Result = - checkedMulUnsigned<uint64_t>(LeftValue, RightValue); - if (!Result) + bool Overflow; + APInt Result = LeftOperand.getAPIntValue().smul_ov( + RightOperand.getAPIntValue(), Overflow); + if (Overflow || + (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) return make_error<OverflowError>(); - return ExpressionValue(*Result); + if (Result.isNegative()) + return ExpressionValue(Result.getSExtValue()); + else + return ExpressionValue(Result.getZExtValue()); } Expected<ExpressionValue> llvm::operator/(const ExpressionValue &LeftOperand, const ExpressionValue &RightOperand) { - // -A / -B == A / B - if (LeftOperand.isNegative() && RightOperand.isNegative()) - return LeftOperand.getAbsolute() / RightOperand.getAbsolute(); - - // Check for divide by zero. - if (RightOperand == ExpressionValue(0)) + // Check for division by zero. + if (RightOperand.getAPIntValue().isZero()) return make_error<OverflowError>(); - // Result will be negative and can underflow. - if (LeftOperand.isNegative() || RightOperand.isNegative()) - return ExpressionValue(0) - - cantFail(LeftOperand.getAbsolute() / RightOperand.getAbsolute()); + bool Overflow; + APInt Result = LeftOperand.getAPIntValue().sdiv_ov( + RightOperand.getAPIntValue(), Overflow); + if (Overflow || + (Result.isNegative() && !Result.isSignedIntN(Result.getBitWidth() - 1))) + return make_error<OverflowError>(); - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - return ExpressionValue(LeftValue / RightValue); + if (Result.isNegative()) + return ExpressionValue(Result.getSExtValue()); + else + return ExpressionValue(Result.getZExtValue()); } Expected<ExpressionValue> llvm::max(const ExpressionValue &LeftOperand, const ExpressionValue &RightOperand) { - if (LeftOperand.isNegative() && RightOperand.isNegative()) { - int64_t LeftValue = cantFail(LeftOperand.getSignedValue()); - int64_t RightValue = cantFail(RightOperand.getSignedValue()); - return ExpressionValue(std::max(LeftValue, RightValue)); - } - - if (!LeftOperand.isNegative() && !RightOperand.isNegative()) { - uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); - uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); - return ExpressionValue(std::max(LeftValue, RightValue)); - } - - if (LeftOperand.isNegative()) - return RightOperand; - - return LeftOperand; + return LeftOperand.getAPIntValue().slt(RightOperand.getAPIntValue()) + ? RightOperand + : LeftOperand; } Expected<ExpressionValue> llvm::min(const ExpressionValue &LeftOperand, const ExpressionValue &RightOperand) { - if (cantFail(max(LeftOperand, RightOperand)) == LeftOperand) + if (cantFail(max(LeftOperand, RightOperand)).getAPIntValue() == + LeftOperand.getAPIntValue()) return RightOperand; return LeftOperand; @@ -493,8 +370,7 @@ Expected<NumericVariable *> Pattern::parseNumericVariableDefinition( // Detect collisions between string and numeric variables when the latter // is created later than the former. - if (Context->DefinedVariableTable.find(Name) != - Context->DefinedVariableTable.end()) + if (Context->DefinedVariableTable.contains(Name)) return ErrorDiagnostic::get( SM, Name, "string variable with name '" + Name + "' already exists"); @@ -1072,8 +948,7 @@ bool Pattern::parsePattern(StringRef PatternStr, StringRef Prefix, // Detect collisions between string and numeric variables when the // former is created later than the latter. - if (Context->GlobalNumericVariableTable.find(Name) != - Context->GlobalNumericVariableTable.end()) { + if (Context->GlobalNumericVariableTable.contains(Name)) { SM.PrintMessage( SMLoc::getFromPointer(Name.data()), SourceMgr::DK_Error, "numeric variable with name '" + Name + "' already exists"); @@ -2753,8 +2628,7 @@ Error FileCheckPatternContext::defineCmdlineVariables( // Detect collisions between string and numeric variables when the former // is created later than the latter. - if (GlobalNumericVariableTable.find(Name) != - GlobalNumericVariableTable.end()) { + if (GlobalNumericVariableTable.contains(Name)) { Errs = joinErrors(std::move(Errs), ErrorDiagnostic::get(SM, Name, "numeric variable with name '" + diff --git a/llvm/lib/FileCheck/FileCheckImpl.h b/llvm/lib/FileCheck/FileCheckImpl.h index fd3568e7a5b0..10fe8d46ffac 100644 --- a/llvm/lib/FileCheck/FileCheckImpl.h +++ b/llvm/lib/FileCheck/FileCheckImpl.h @@ -15,6 +15,7 @@ #ifndef LLVM_LIB_FILECHECK_FILECHECKIMPL_H #define LLVM_LIB_FILECHECK_FILECHECKIMPL_H +#include "llvm/ADT/APInt.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/FileCheck/FileCheck.h" @@ -120,38 +121,14 @@ public: /// Class representing a numeric value. class ExpressionValue { private: - uint64_t Value; - bool Negative; + APInt Value; public: + // Store signed and unsigned 64-bit integers in a signed 65-bit APInt. template <class T> - explicit ExpressionValue(T Val) : Value(Val), Negative(Val < 0) {} + explicit ExpressionValue(T Val) : Value(65, Val, /*isSigned=*/Val < 0) {} - bool operator==(const ExpressionValue &Other) const { - return Value == Other.Value && isNegative() == Other.isNegative(); - } - - bool operator!=(const ExpressionValue &Other) const { - return !(*this == Other); - } - - /// Returns true if value is signed and negative, false otherwise. - bool isNegative() const { - assert((Value != 0 || !Negative) && "Unexpected negative zero!"); - 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; + APInt getAPIntValue() const { return Value; } }; /// Performs operation and \returns its result or an error in case of failure, @@ -269,7 +246,7 @@ private: std::optional<ExpressionValue> Value; /// The input buffer's string from which Value was parsed, or std::nullopt. - /// See comments on getStringValue for a discussion of the None case. + /// See comments on getStringValue for a discussion of the std::nullopt case. std::optional<StringRef> StrValue; /// Line number where this variable is defined, or std::nullopt if defined @@ -280,7 +257,7 @@ private: public: /// Constructor for a variable \p Name with implicit format \p ImplicitFormat /// defined at line \p DefLineNumber or defined before input is parsed if - /// \p DefLineNumber is None. + /// \p DefLineNumber is std::nullopt. explicit NumericVariable(StringRef Name, ExpressionFormat ImplicitFormat, std::optional<size_t> DefLineNumber = std::nullopt) : Name(Name), ImplicitFormat(ImplicitFormat), @@ -304,7 +281,7 @@ public: /// Sets value of this numeric variable to \p NewValue, and sets the input /// buffer string from which it was parsed to \p NewStrValue. See comments on - /// getStringValue for a discussion of when the latter can be None. + /// getStringValue for a discussion of when the latter can be std::nullopt. void setValue(ExpressionValue NewValue, std::optional<StringRef> NewStrValue = std::nullopt) { Value = NewValue; |