Commit ffc71c03 authored by Justin Schuh's avatar Justin Schuh Committed by Commit Bot

Reorder saturation calculation for ClampAddOp and ClampSupOp

The order of operations changed in crrev.com/505494 with C++14
constexpr optimizations. However, that change appears to have regressed
performance in some cases. So, this CL tweaks the code to match the
old structure and trigger the same compiler optimization heuristics.

Bug: 770832
Change-Id: I28f57ddf53825619eb73c9a92c663fc8463e16a7
Reviewed-on: https://chromium-review.googlesource.com/696721Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Commit-Queue: Justin Schuh <jschuh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#506078}
parent 264d3393
......@@ -82,31 +82,30 @@ struct ClampedAddOp<T,
if (ClampedAddFastOp<T, U>::is_supported)
return ClampedAddFastOp<T, U>::template Do<V>(x, y);
// This is structured as a nested ternary to trigger the necessary
// optimization heuristics in MSVC and Clang.
const V saturated =
IsTypeInRangeForNumericType<V, T>::value
? (IsTypeInRangeForNumericType<V, U>::value
// Optimize for a compile-time constant in the common case.
? CommonMaxOrMin<V>(
(IsCompileTimeConstant(x) && IsValueNegative(x)) ||
IsValueNegative(y))
// Otherwise the out-of-range-type determines the saturation.
: CommonMaxOrMin<V>(IsValueNegative(y)))
: CommonMaxOrMin<V>(IsValueNegative(x));
// Pick a destination type wide enough to compute the saturation direction.
// The saturation check in the final return statement covers the case where
// one type is out-of-bounds. It's structured this way to avoid unnecessary
// run-time conversions when we have a compile-time-constant.
// We already computed the saturation value, so it's structured this way to
// avoid run-time conversions when we have a compile-time-constant.
using Promotion = typename std::conditional_t<
IsTypeInRangeForNumericType<V, T>::value ||
IsTypeInRangeForNumericType<V, U>::value,
V, typename BigEnoughPromotion<T, U>::type>;
Promotion result;
if (BASE_NUMERICS_LIKELY((CheckedAddOp<T, U>::Do(x, y, &result))))
return saturated_cast<V>(result);
// This is the normal saturation case, which includes a compile-time
// constant optimization.
if (IsTypeInRangeForNumericType<V, T>::value &&
IsTypeInRangeForNumericType<V, U>::value) {
return CommonMaxOrMin<V>(
(IsCompileTimeConstant(x) && IsValueNegative(x)) ||
IsValueNegative(y));
}
// Otherwise the out-of-range-type determines the saturation direction.
return IsTypeInRangeForNumericType<V, T>::value
? CommonMaxOrMin<V>(IsValueNegative(y))
: CommonMaxOrMin<V>(IsValueNegative(x));
return BASE_NUMERICS_LIKELY((CheckedAddOp<T, U>::Do(x, y, &result)))
? saturated_cast<V>(result)
: saturated;
}
};
......@@ -125,31 +124,30 @@ struct ClampedSubOp<T,
if (ClampedSubFastOp<T, U>::is_supported)
return ClampedSubFastOp<T, U>::template Do<V>(x, y);
// This is structured as a nested ternary to trigger the necessary
// optimization heuristics in MSVC and Clang.
const V saturated =
IsTypeInRangeForNumericType<V, T>::value
? (IsTypeInRangeForNumericType<V, U>::value
// Optimize for a compile-time constant in the common case.
? CommonMaxOrMin<V>(
(IsCompileTimeConstant(x) && IsValueNegative(x)) ||
!IsValueNegative(y))
// Otherwise the out-of-range-type determines the saturation.
: CommonMaxOrMin<V>(!IsValueNegative(y)))
: CommonMaxOrMin<V>(IsValueNegative(x));
// Pick a destination type wide enough to compute the saturation direction.
// The saturation check in the final return statement covers the case where
// one type is out-of-bounds. It's structured this way to avoid unnecessary
// run-time conversions when we have a compile-time-constant.
// We already computed the saturation value, so it's structured this way to
// avoid run-time conversions when we have a compile-time-constant.
using Promotion = typename std::conditional_t<
IsTypeInRangeForNumericType<V, T>::value ||
IsTypeInRangeForNumericType<V, U>::value,
V, typename BigEnoughPromotion<T, U>::type>;
Promotion result;
if (BASE_NUMERICS_LIKELY((CheckedSubOp<T, U>::Do(x, y, &result))))
return saturated_cast<V>(result);
// This is the normal saturation case, which includes a compile-time
// constant optimization.
if (IsTypeInRangeForNumericType<V, T>::value &&
IsTypeInRangeForNumericType<V, U>::value) {
return CommonMaxOrMin<V>(
(IsCompileTimeConstant(x) && IsValueNegative(x)) ||
!IsValueNegative(y));
}
// Otherwise the out-of-range-type determines the saturation direction.
return IsTypeInRangeForNumericType<V, T>::value
? CommonMaxOrMin<V>(!IsValueNegative(y))
: CommonMaxOrMin<V>(IsValueNegative(x));
return BASE_NUMERICS_LIKELY((CheckedSubOp<T, U>::Do(x, y, &result)))
? saturated_cast<V>(result)
: saturated;
}
};
......
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