LCOV - code coverage report
Current view: top level - src/base - overflowing-math.h (source / functions) Hit Total Coverage
Test: app.info Lines: 22 22 100.0 %
Date: 2019-04-18 Functions: 16 16 100.0 %

          Line data    Source code
       1             : // Copyright 2019 the V8 project 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 V8_BASE_OVERFLOWING_MATH_H_
       6             : #define V8_BASE_OVERFLOWING_MATH_H_
       7             : 
       8             : #include <stdint.h>
       9             : 
      10             : #include <cmath>
      11             : #include <type_traits>
      12             : 
      13             : #include "src/base/macros.h"
      14             : 
      15             : namespace v8 {
      16             : namespace base {
      17             : 
      18             : // Helpers for performing overflowing arithmetic operations without relying
      19             : // on C++ undefined behavior.
      20             : #define ASSERT_SIGNED_INTEGER_TYPE(Type)                                      \
      21             :   static_assert(std::is_integral<Type>::value && std::is_signed<Type>::value, \
      22             :                 "use this for signed integer types");
      23             : #define OP_WITH_WRAPAROUND(Name, OP)                                      \
      24             :   template <typename signed_type>                                         \
      25             :   inline signed_type Name##WithWraparound(signed_type a, signed_type b) { \
      26             :     ASSERT_SIGNED_INTEGER_TYPE(signed_type);                              \
      27             :     using unsigned_type = typename std::make_unsigned<signed_type>::type; \
      28             :     unsigned_type a_unsigned = static_cast<unsigned_type>(a);             \
      29             :     unsigned_type b_unsigned = static_cast<unsigned_type>(b);             \
      30             :     unsigned_type result = a_unsigned OP b_unsigned;                      \
      31             :     return static_cast<signed_type>(result);                              \
      32             :   }
      33             : 
      34    17309589 : OP_WITH_WRAPAROUND(Add, +)
      35     2206007 : OP_WITH_WRAPAROUND(Sub, -)
      36     5224160 : OP_WITH_WRAPAROUND(Mul, *)
      37             : 
      38             : // 16-bit integers are special due to C++'s implicit conversion rules.
      39             : // See https://bugs.llvm.org/show_bug.cgi?id=25580.
      40             : template <>
      41         972 : inline int16_t MulWithWraparound(int16_t a, int16_t b) {
      42        3564 :   uint32_t a_unsigned = static_cast<uint32_t>(a);
      43        3564 :   uint32_t b_unsigned = static_cast<uint32_t>(b);
      44        3564 :   uint32_t result = a_unsigned * b_unsigned;
      45        3564 :   return static_cast<int16_t>(static_cast<uint16_t>(result));
      46             : }
      47             : 
      48             : #undef OP_WITH_WRAPAROUND
      49             : 
      50             : template <typename signed_type>
      51         912 : inline signed_type NegateWithWraparound(signed_type a) {
      52             :   ASSERT_SIGNED_INTEGER_TYPE(signed_type);
      53     2091607 :   if (a == std::numeric_limits<signed_type>::min()) return a;
      54     2089096 :   return -a;
      55             : }
      56             : 
      57             : template <typename signed_type>
      58             : inline signed_type ShlWithWraparound(signed_type a, signed_type b) {
      59             :   ASSERT_SIGNED_INTEGER_TYPE(signed_type);
      60             :   using unsigned_type = typename std::make_unsigned<signed_type>::type;
      61             :   const unsigned_type kMask = (sizeof(a) * 8) - 1;
      62      807440 :   return static_cast<signed_type>(static_cast<unsigned_type>(a) << (b & kMask));
      63             : }
      64             : 
      65             : #undef ASSERT_SIGNED_INTEGER_TYPE
      66             : 
      67             : // Returns the quotient x/y, avoiding C++ undefined behavior if y == 0.
      68             : template <typename T>
      69     2420445 : inline T Divide(T x, T y) {
      70     2423473 :   if (y != 0) return x / y;
      71       10161 :   if (x == 0 || x != x) return std::numeric_limits<T>::quiet_NaN();
      72       17886 :   if ((x >= 0) == (std::signbit(y) == 0)) {
      73             :     return std::numeric_limits<T>::infinity();
      74             :   }
      75        2365 :   return -std::numeric_limits<T>::infinity();
      76             : }
      77             : 
      78        2592 : inline float Recip(float a) { return Divide(1.0f, a); }
      79             : 
      80        3024 : inline float RecipSqrt(float a) {
      81        5964 :   if (a != 0) return 1.0f / std::sqrt(a);
      82          84 :   if (std::signbit(a) == 0) return std::numeric_limits<float>::infinity();
      83          28 :   return -std::numeric_limits<float>::infinity();
      84             : }
      85             : 
      86             : }  // namespace base
      87             : }  // namespace v8
      88             : 
      89             : #endif  // V8_BASE_OVERFLOWING_MATH_H_

Generated by: LCOV version 1.10