Skip to content

Commit

Permalink
[FileCheck, 2/4] NFC: Switch to APInt getter for ExpressionValue
Browse files Browse the repository at this point in the history
Use an APInt getter as the only interface to getting the value out of an
ExpressionValue. This paves the way to switch ExpressionValue to handle
any integer without causing too big of a patch.

Reviewed By: arichardson

Differential Revision: https://reviews.llvm.org/D154429
  • Loading branch information
RoboTux committed Jul 4, 2023
1 parent cf57fcf commit fc0d1c0
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 338 deletions.
230 changes: 66 additions & 164 deletions llvm/lib/FileCheck/FileCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,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();

Expand Down Expand Up @@ -155,183 +159,81 @@ ExpressionFormat::valueFromStringRepr(StringRef StrVal,
return ExpressionValue(UnsignedValue);
}

Expected<int64_t> ExpressionValue::getSignedValue() const {
std::optional<int64_t> SignedValue = Value.trySExtValue();
if (!SignedValue)
return make_error<OverflowError>();
return *SignedValue;
}

Expected<uint64_t> ExpressionValue::getUnsignedValue() const {
std::optional<int64_t> UnsignedValue = Value.tryZExtValue();
if (!UnsignedValue)
return make_error<OverflowError>();

return *UnsignedValue;
}

ExpressionValue ExpressionValue::getAbsolute() const {
unsigned bitwidth = Value.getBitWidth();
assert(!Value.isNegative() || Value.isSignedIntN(bitwidth - 1));
return ExpressionValue(Value.abs().getZExtValue());
}

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;
Expand Down
23 changes: 1 addition & 22 deletions llvm/lib/FileCheck/FileCheckImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,28 +128,7 @@ class ExpressionValue {
template <class T>
explicit ExpressionValue(T Val) : Value(65, Val, /*isSigned=*/Val < 0) {}

bool operator==(const ExpressionValue &Other) const {
return Value == Other.Value;
}

bool operator!=(const ExpressionValue &Other) const {
return !(*this == Other);
}

/// Returns true if value is signed and negative, false otherwise.
bool isNegative() const { return Value.isNegative(); }

/// \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,
Expand Down
Loading

0 comments on commit fc0d1c0

Please sign in to comment.