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 { ...@@ -21,6 +21,9 @@ class CheckedNumeric {
"CheckedNumeric<T>: T must be a numeric type."); "CheckedNumeric<T>: T must be a numeric type.");
public: public:
template <typename Src>
friend class CheckedNumeric;
using type = T; using type = T;
constexpr CheckedNumeric() = default; constexpr CheckedNumeric() = default;
...@@ -30,9 +33,6 @@ class CheckedNumeric { ...@@ -30,9 +33,6 @@ class CheckedNumeric {
constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs) constexpr CheckedNumeric(const CheckedNumeric<Src>& rhs)
: state_(rhs.state_.value(), rhs.IsValid()) {} : state_(rhs.state_.value(), rhs.IsValid()) {}
template <typename Src>
friend class CheckedNumeric;
// This is not an explicit constructor because we implicitly upgrade regular // This is not an explicit constructor because we implicitly upgrade regular
// numerics to CheckedNumerics to make them easier to use. // numerics to CheckedNumerics to make them easier to use.
template <typename Src> template <typename Src>
...@@ -138,18 +138,17 @@ class CheckedNumeric { ...@@ -138,18 +138,17 @@ class CheckedNumeric {
constexpr CheckedNumeric& operator^=(const Src rhs); constexpr CheckedNumeric& operator^=(const Src rhs);
constexpr CheckedNumeric operator-() const { constexpr CheckedNumeric operator-() const {
// The negation of two's complement int min is int min, so we simply // Use an optimized code path for a known run-time variable.
// check for that in the constexpr case. if (!MustTreatAsConstexpr(state_.value()) && std::is_signed<T>::value &&
// We use an optimized code path for a known run-time variable. std::is_floating_point<T>::value) {
return MustTreatAsConstexpr(state_.value()) || !std::is_signed<T>::value || return FastRuntimeNegate();
std::is_floating_point<T>::value }
? CheckedNumeric<T>( // The negation of two's complement int min is int min.
NegateWrapper(state_.value()), const bool is_valid =
IsValid() && (!std::is_signed<T>::value || IsValid() &&
std::is_floating_point<T>::value || (!std::is_signed<T>::value || std::is_floating_point<T>::value ||
NegateWrapper(state_.value()) != NegateWrapper(state_.value()) != std::numeric_limits<T>::lowest());
std::numeric_limits<T>::lowest())) return CheckedNumeric<T>(NegateWrapper(state_.value()), is_valid);
: FastRuntimeNegate();
} }
constexpr CheckedNumeric operator~() const { constexpr CheckedNumeric operator~() const {
...@@ -199,7 +198,8 @@ class CheckedNumeric { ...@@ -199,7 +198,8 @@ class CheckedNumeric {
} }
constexpr CheckedNumeric operator--(int) { 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; *this -= 1;
return value; return value;
} }
...@@ -212,7 +212,7 @@ class CheckedNumeric { ...@@ -212,7 +212,7 @@ class CheckedNumeric {
static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) { static constexpr CheckedNumeric MathOp(const L lhs, const R rhs) {
using Math = typename MathWrapper<M, L, R>::math; using Math = typename MathWrapper<M, L, R>::math;
T result = 0; T result = 0;
bool is_valid = const bool is_valid =
Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) && Wrapper<L>::is_valid(lhs) && Wrapper<R>::is_valid(rhs) &&
Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result); Math::Do(Wrapper<L>::value(lhs), Wrapper<R>::value(rhs), &result);
return CheckedNumeric<T>(result, is_valid); return CheckedNumeric<T>(result, is_valid);
...@@ -223,8 +223,9 @@ class CheckedNumeric { ...@@ -223,8 +223,9 @@ class CheckedNumeric {
constexpr CheckedNumeric& MathOp(const R rhs) { constexpr CheckedNumeric& MathOp(const R rhs) {
using Math = typename MathWrapper<M, T, R>::math; using Math = typename MathWrapper<M, T, R>::math;
T result = 0; // Using T as the destination saves a range check. 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 =
Math::Do(state_.value(), Wrapper<R>::value(rhs), &result); state_.is_valid() && Wrapper<R>::is_valid(rhs) &&
Math::Do(state_.value(), Wrapper<R>::value(rhs), &result);
*this = CheckedNumeric<T>(result, is_valid); *this = CheckedNumeric<T>(result, is_valid);
return *this; return *this;
} }
...@@ -234,7 +235,7 @@ class CheckedNumeric { ...@@ -234,7 +235,7 @@ class CheckedNumeric {
CheckedNumeric FastRuntimeNegate() const { CheckedNumeric FastRuntimeNegate() const {
T result; 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); return CheckedNumeric<T>(result, IsValid() && success);
} }
...@@ -335,17 +336,17 @@ BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min) ...@@ -335,17 +336,17 @@ BASE_NUMERIC_ARITHMETIC_VARIADIC(Checked, Check, Min)
// bad, we trigger the CHECK condition here. // bad, we trigger the CHECK condition here.
template <typename L, typename R> template <typename L, typename R>
L* operator+(L* lhs, const StrictNumeric<R> rhs) { 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))) CheckMul(sizeof(L), static_cast<R>(rhs)))
.template ValueOrDie<uintptr_t>(); .template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result); return reinterpret_cast<L*>(result);
} }
template <typename L, typename R> template <typename L, typename R>
L* operator-(L* lhs, const StrictNumeric<R> rhs) { 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))) CheckMul(sizeof(L), static_cast<R>(rhs)))
.template ValueOrDie<uintptr_t>(); .template ValueOrDie<uintptr_t>();
return reinterpret_cast<L*>(result); return reinterpret_cast<L*>(result);
} }
......
This diff is collapsed.
...@@ -36,8 +36,9 @@ struct CheckedMulFastAsmOp { ...@@ -36,8 +36,9 @@ struct CheckedMulFastAsmOp {
Promotion presult; Promotion presult;
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y); presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
const bool is_valid = IsValueInRangeForNumericType<V>(presult);
*result = static_cast<V>(presult); *result = static_cast<V>(presult);
return IsValueInRangeForNumericType<V>(presult); return is_valid;
} }
}; };
...@@ -104,9 +105,9 @@ struct ClampedMulFastAsmOp { ...@@ -104,9 +105,9 @@ struct ClampedMulFastAsmOp {
if (!IsIntegerArithmeticSafe<int32_t, T, U>::value && if (!IsIntegerArithmeticSafe<int32_t, T, U>::value &&
!IsIntegerArithmeticSafe<uint32_t, T, U>::value) { !IsIntegerArithmeticSafe<uint32_t, T, U>::value) {
V result; V result;
if (CheckedMulFastAsmOp<T, U>::Do(x, y, &result)) return CheckedMulFastAsmOp<T, U>::Do(x, y, &result)
return result; ? result
return CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y)); : CommonMaxOrMin<V>(IsValueNegative(x) ^ IsValueNegative(y));
} }
assert((FastIntegerArithmeticPromotion<T, U>::is_contained)); 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