Commit 37b8843a authored by Peter Kasting's avatar Peter Kasting Committed by Chromium LUCI CQ

Checked math cleanup.

* Add const to various locally-const variables
* Remove const from function parameters
* Consistently compute result validity before setting the result, in
  preparation for making the latter conditional on the former
* Follow style guide better
* Reduce some deep indentation
* Brevity

None of these changes are intended to affect functionality.

Bug: none
Change-Id: I134e055904630f30054baafaa4b6cdb23d4eb16b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2585365
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Auto-Submit: Peter Kasting <pkasting@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835899}
parent af9bb675
......@@ -21,6 +21,9 @@ class CheckedNumeric {
"CheckedNumeric<T>: T must be a numeric type.");
public:
template <typename Src>
friend class CheckedNumeric;
using type = T;
constexpr CheckedNumeric() = default;
......@@ -30,9 +33,6 @@ class CheckedNumeric {
constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
: state_(rhs.state_.value(), rhs.IsValid()) {}
template <typename Src>
friend class CheckedNumeric;
// This is not an explicit constructor because we implicitly upgrade regular
// numerics to CheckedNumerics to make them easier to use.
template <typename Src>
......@@ -138,18 +138,17 @@ class CheckedNumeric {
constexpr CheckedNumeric& operator^=(const Src rhs);
constexpr CheckedNumeric operator-() const {
// The negation of two's complement int min is int min, so we simply
// check for that in the constexpr case.
// We use an optimized code path for a known run-time variable.
return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value ||
std::is_floating_point<T>::value
? CheckedNumeric<T>(
NegateWrapper(state_.value()),
IsValid() && (!std::is_signed<T>::value ||
std::is_floating_point<T>::value ||
NegateWrapper(state_.value()) !=
std::numeric_limits<T>::lowest()))
: FastRuntimeNegate();
// Use an optimized code path for a known run-time variable.
if (!MustTreatAsConstexpr(state_.value()) && std::is_signed<T>::value &&
std::is_floating_point<T>::value) {
return FastRuntimeNegate();
}
// The negation of two's complement int min is int min.
const bool is_valid =
IsValid() &&
(!std::is_signed<T>::value || std::is_floating_point<T>::value ||
NegateWrapper(state_.value()) != std::numeric_limits<T>::lowest());
return CheckedNumeric<T>(NegateWrapper(state_.value()), is_valid);
}
constexpr CheckedNumeric operator~() const {
......@@ -199,7 +198,8 @@ class CheckedNumeric {
}
constexpr CheckedNumeric operator--(int) {
CheckedNumeric value = *this;
// TODO(pkasting): Consider std::exchange() once it's constexpr in C++20.
const CheckedNumeric value = *this;
*this -= 1;
return value;
}
......@@ -212,7 +212,7 @@ class CheckedNumeric {
static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
using Math = typename MathWrapper<M, L, R>::math;
T result = 0;
bool is_valid =
const bool is_valid =
Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
return CheckedNumeric<T>(result, is_valid);
......@@ -223,7 +223,8 @@ class CheckedNumeric {
constexpr CheckedNumeric& MathOp(const R rhs) {
using Math = typename MathWrapper<M, T, R>::math;
T result = 0; // Using T as the destination saves a range check.
bool is_valid = state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
const bool is_valid =
state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
*this = CheckedNumeric<T>(result, is_valid);
return *this;
......@@ -234,7 +235,7 @@ class CheckedNumeric {
CheckedNumeric FastRuntimeNegate() const {
T result;
bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
const bool success = CheckedSubOp<T, T>::Do(T(0), state_.value(), &result);
return CheckedNumeric<T>(result, IsValid() && success);
}
......@@ -335,7 +336,7 @@ BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min)
// bad, we trigger the CHECK condition here.
template <typename L, typename R>
L* operator+(L* lhs, const StrictNumeric<R> rhs) {
uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
const uintptr_t result = CheckAdd(reinterpret_cast<uintptr_t>(lhs),
CheckMul(sizeof(L), static_cast<R>(rhs)))
.template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result);
......@@ -343,7 +344,7 @@ L* operator+(L* lhs, const StrictNumeric<R> rhs) {
template <typename L, typename R>
L* operator-(L* lhs, const StrictNumeric<R> rhs) {
uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
const uintptr_t result = CheckSub(reinterpret_cast<uintptr_t>(lhs),
CheckMul(sizeof(L), static_cast<R>(rhs)))
.template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result);
......
This diff is collapsed.
......@@ -36,8 +36,9 @@ struct CheckedMulFastAsmOp {
Promotion presult;
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
const bool is_valid = IsValueInRangeForNumericType<V>(presult);
*result = static_cast<V>(presult);
return IsValueInRangeForNumericType<V>(presult);
return is_valid;
}
};
......@@ -104,9 +105,9 @@ struct ClampedMulFastAsmOp {
if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
!IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
V result;
if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result))
return result;
return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
? result
: CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
}
assert((FastIntegerArithmeticPromotion<T, U>::is_contained));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment