diff --git a/llvm/lib/Support/FileCheck.cpp b/llvm/lib/Support/FileCheck.cpp --- a/llvm/lib/Support/FileCheck.cpp +++ b/llvm/lib/Support/FileCheck.cpp @@ -230,6 +230,70 @@ } } +Expected 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!"); + uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); + + // Result will be negative and thus might underflow. + if (LeftOperand.isNegative()) { + uint64_t LeftValue = cantFail(LeftOperand.getAbsolute().getUnsignedValue()); + Optional Result = + checkedMulUnsigned(LeftValue, RightValue); + if (!Result) + return make_error(); + // Result cannot be represented as int64_t. + if (*Result > (uint64_t)std::numeric_limits::max() + 1) + return make_error(); + + return ExpressionValue(-static_cast(*Result)); + } + + uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); + Optional Result = + checkedMulUnsigned(LeftValue, RightValue); + if (!Result) + return make_error(); + + return ExpressionValue(*Result); +} + +Expected 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)) + return make_error(); + + // Result will be negative and thus might underflow. + if (LeftOperand.isNegative() || RightOperand.isNegative()) { + uint64_t LeftValue = cantFail(LeftOperand.getAbsolute().getUnsignedValue()); + uint64_t RightValue = + cantFail(RightOperand.getAbsolute().getUnsignedValue()); + uint64_t ResultValue = LeftValue / RightValue; + // Result cannot be represented as int64_t. + if (ResultValue > (uint64_t)std::numeric_limits::max() + 1) + return make_error(); + + return ExpressionValue(-static_cast(ResultValue)); + } + + uint64_t LeftValue = cantFail(LeftOperand.getUnsignedValue()); + uint64_t RightValue = cantFail(RightOperand.getUnsignedValue()); + return ExpressionValue(LeftValue / RightValue); +} + Expected NumericVariableUse::eval() const { Optional Value = Variable->getValue(); if (Value) diff --git a/llvm/lib/Support/FileCheckImpl.h b/llvm/lib/Support/FileCheckImpl.h --- a/llvm/lib/Support/FileCheckImpl.h +++ b/llvm/lib/Support/FileCheckImpl.h @@ -64,8 +64,8 @@ return Value != Kind::NoFormat && Value == Other.Value; } - bool operator!=(const ExpressionFormat &other) const { - return !(*this == other); + bool operator!=(const ExpressionFormat &Other) const { + return !(*this == Other); } bool operator==(Kind OtherValue) const { return Value == OtherValue; } @@ -119,8 +119,19 @@ template explicit ExpressionValue(T Val) : Value(Val), Negative(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 { return Negative; } + 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. @@ -141,6 +152,10 @@ const ExpressionValue &Rhs); Expected operator-(const ExpressionValue &Lhs, const ExpressionValue &Rhs); +Expected operator*(const ExpressionValue &Lhs, + const ExpressionValue &Rhs); +Expected operator/(const ExpressionValue &Lhs, + const ExpressionValue &Rhs); /// Base class representing the AST of a given expression. class ExpressionAST { diff --git a/llvm/unittests/Support/FileCheckTest.cpp b/llvm/unittests/Support/FileCheckTest.cpp --- a/llvm/unittests/Support/FileCheckTest.cpp +++ b/llvm/unittests/Support/FileCheckTest.cpp @@ -478,6 +478,93 @@ expectOperationValueResult(operator-, 10, 11, -1); } +TEST_F(FileCheckTest, ExpressionValueMultiplication) { + // Test negative and positive value with negative result. + expectOperationValueResult(operator*, -3, 10, -30); + expectOperationValueResult(operator*, 2, -17, -34); + expectOperationValueResult(operator*, MinInt64, 1, MinInt64); + expectOperationValueResult(operator*, 1, MinInt64, MinInt64); + expectOperationValueResult(operator*, static_cast(MaxInt64) + 1, -1, + MinInt64); + expectOperationValueResult(operator*, -1, static_cast(MaxInt64) + 1, + MinInt64); + + // Test both negative values with positive result. + expectOperationValueResult(operator*, -3, -10, 30); + expectOperationValueResult(operator*, -2, -17, 34); + + // Test both positive values with positive result. + expectOperationValueResult(operator*, 3, 10, 30); + expectOperationValueResult(operator*, 2, 17, 34); + + // Test negative result that underflows. + expectOperationValueResult(operator*, -10, MaxInt64); + expectOperationValueResult(operator*, MaxInt64, -10); + expectOperationValueResult(operator*, 10, MinInt64); + expectOperationValueResult(operator*, MinInt64, 10); + + // Test positive result that overflows. + expectOperationValueResult(operator*, 10, MaxUint64); + expectOperationValueResult(operator*, MaxUint64, 10); + expectOperationValueResult(operator*, MinInt64, -10); + expectOperationValueResult(operator*, -10, MinInt64); +} + +TEST_F(FileCheckTest, ExpressionValueDivision) { + // Test negative and positive value with negative result. + expectOperationValueResult(operator/, -30, 10, -3); + expectOperationValueResult(operator/, 34, -17, -2); + expectOperationValueResult(operator/, MinInt64, 1, MinInt64); + expectOperationValueResult(operator/, static_cast(MaxInt64)+1, -1, + MinInt64); + + // Test both negative values with positive result. + expectOperationValueResult(operator/, -30, -10, 3); + expectOperationValueResult(operator/, -34, -17, 2); + + // Test both positive values with positive result. + expectOperationValueResult(operator/, 30, 10, 3); + expectOperationValueResult(operator/, 34, 17, 2); + + // Test divide by zero. + expectOperationValueResult(operator/, -10, 0); + expectOperationValueResult(operator/, 10, 0); + + // Test negative result that underflows. + expectOperationValueResult(operator/, MaxUint64, -1); + expectOperationValueResult(operator/, static_cast(MaxInt64)+2, -1); +} + +TEST_F(FileCheckTest, ExpressionValueEquality) { + // Test negative and positive value. + EXPECT_EQ(ExpressionValue(5) == ExpressionValue(-3), 0); + EXPECT_EQ(ExpressionValue(5) != ExpressionValue(-3), 1); + EXPECT_EQ(ExpressionValue(-2) == ExpressionValue(6), 0); + EXPECT_EQ(ExpressionValue(-2) != ExpressionValue(6), 1); + + // Test both negative values. + EXPECT_EQ(ExpressionValue(-2) == ExpressionValue(-7), 0); + EXPECT_EQ(ExpressionValue(-2) != ExpressionValue(-7), 1); + EXPECT_EQ(ExpressionValue(-3) == ExpressionValue(-3), 1); + EXPECT_EQ(ExpressionValue(-3) != ExpressionValue(-3), 0); + + // Test both positive values. + EXPECT_EQ(ExpressionValue(1) == ExpressionValue(9), 0); + EXPECT_EQ(ExpressionValue(1) != ExpressionValue(9), 1); + EXPECT_EQ(ExpressionValue(1) == ExpressionValue(1), 1); + EXPECT_EQ(ExpressionValue(1) != ExpressionValue(1), 0); + + // Check the signedness of zero doesn't affect equality. + EXPECT_EQ(ExpressionValue(0) == ExpressionValue(0), 1); + EXPECT_EQ(ExpressionValue(0) != ExpressionValue(0), 0); + EXPECT_EQ(ExpressionValue(0) == ExpressionValue(-0), 1); + EXPECT_EQ(ExpressionValue(0) != ExpressionValue(-0), 0); + EXPECT_EQ(ExpressionValue(-0) == ExpressionValue(0), 1); + EXPECT_EQ(ExpressionValue(-0) != ExpressionValue(0), 0); + EXPECT_EQ(ExpressionValue(-0) == ExpressionValue(-0), 1); + EXPECT_EQ(ExpressionValue(-0) != ExpressionValue(-0), 0); +} + TEST_F(FileCheckTest, Literal) { SourceMgr SM;