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