• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)25 ALWAYS_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)39 ALWAYS_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)53 ALWAYS_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)59 ALWAYS_INLINE int32_t SaturatedAbsolute(int32_t a) {
60   if (a >= 0)
61     return a;
62   return SaturatedNegative(a);
63 }
64 
GetMaxSaturatedSetResultForTesting(int fractional_shift)65 ALWAYS_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)72 ALWAYS_INLINE int GetMinSaturatedSetResultForTesting(int fractional_shift) {
73   return std::numeric_limits<int>::min();
74 }
75 
76 template <int fractional_shift>
SaturatedSet(int value)77 ALWAYS_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)94 ALWAYS_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