1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_NUMERICS_SATURATED_ARITHMETIC_H_ 6 #define BASE_NUMERICS_SATURATED_ARITHMETIC_H_ 7 8 #include <stdint.h> 9 10 #include <limits> 11 12 #include "base/compiler_specific.h" 13 14 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) && \ 15 defined(COMPILER_GCC) && !defined(OS_NACL) && __OPTIMIZE__ 16 17 // If we're building ARM 32-bit on GCC we replace the C++ versions with some 18 // native ARM assembly for speed. 19 #include "base/numerics/saturated_arithmetic_arm.h" 20 21 #else 22 23 namespace base { 24 SaturatedAddition(int32_t a,int32_t b)25ALWAYS_INLINE int32_t SaturatedAddition(int32_t a, int32_t b) { 26 uint32_t ua = a; 27 uint32_t ub = b; 28 uint32_t result = ua + ub; 29 30 // Can only overflow if the signed bit of the two values match. If the 31 // signed bit of the result and one of the values differ it overflowed. 32 // The branch compiles to a CMOVNS instruction on x86. 33 if (~(ua ^ ub) & (result ^ ua) & (1 << 31)) 34 return std::numeric_limits<int>::max() + (ua >> 31); 35 36 return result; 37 } 38 SaturatedSubtraction(int32_t a,int32_t b)39ALWAYS_INLINE int32_t SaturatedSubtraction(int32_t a, int32_t b) { 40 uint32_t ua = a; 41 uint32_t ub = b; 42 uint32_t result = ua - ub; 43 44 // Can only overflow if the signed bit of the two input values differ. If 45 // the signed bit of the result and the first value differ it overflowed. 46 // The branch compiles to a CMOVNS instruction on x86. 47 if ((ua ^ ub) & (result ^ ua) & (1 << 31)) 48 return std::numeric_limits<int>::max() + (ua >> 31); 49 50 return result; 51 } 52 SaturatedNegative(int32_t a)53ALWAYS_INLINE int32_t SaturatedNegative(int32_t a) { 54 if (UNLIKELY(a == std::numeric_limits<int>::min())) 55 return std::numeric_limits<int>::max(); 56 return -a; 57 } 58 SaturatedAbsolute(int32_t a)59ALWAYS_INLINE int32_t SaturatedAbsolute(int32_t a) { 60 if (a >= 0) 61 return a; 62 return SaturatedNegative(a); 63 } 64 GetMaxSaturatedSetResultForTesting(int fractional_shift)65ALWAYS_INLINE int GetMaxSaturatedSetResultForTesting(int fractional_shift) { 66 // For C version the set function maxes out to max int, this differs from 67 // the ARM asm version, see saturated_arithmetic_arm.h for the equivalent asm 68 // version. 69 return std::numeric_limits<int>::max(); 70 } 71 GetMinSaturatedSetResultForTesting(int fractional_shift)72ALWAYS_INLINE int GetMinSaturatedSetResultForTesting(int fractional_shift) { 73 return std::numeric_limits<int>::min(); 74 } 75 76 template <int fractional_shift> SaturatedSet(int value)77ALWAYS_INLINE int SaturatedSet(int value) { 78 const int kIntMaxForLayoutUnit = 79 std::numeric_limits<int>::max() >> fractional_shift; 80 81 const int kIntMinForLayoutUnit = 82 std::numeric_limits<int>::min() >> fractional_shift; 83 84 if (value > kIntMaxForLayoutUnit) 85 return std::numeric_limits<int>::max(); 86 87 if (value < kIntMinForLayoutUnit) 88 return std::numeric_limits<int>::min(); 89 90 return value << fractional_shift; 91 } 92 93 template <int fractional_shift> SaturatedSet(unsigned value)94ALWAYS_INLINE int SaturatedSet(unsigned value) { 95 const unsigned kIntMaxForLayoutUnit = 96 std::numeric_limits<int>::max() >> fractional_shift; 97 98 if (value >= kIntMaxForLayoutUnit) 99 return std::numeric_limits<int>::max(); 100 101 return value << fractional_shift; 102 } 103 104 } // namespace base 105 106 #endif // CPU(ARM) && COMPILER(GCC) 107 #endif // BASE_NUMERICS_SATURATED_ARITHMETIC_H_ 108