| /* Definitions for simple data type for real numbers. |
| Copyright (C) 2002-2019 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef GCC_SREAL_H |
| #define GCC_SREAL_H |
| |
| #define SREAL_PART_BITS 31 |
| |
| #define UINT64_BITS 64 |
| |
| #define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2)) |
| #define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1) |
| #define SREAL_MAX_EXP (INT_MAX / 4) |
| |
| #define SREAL_BITS SREAL_PART_BITS |
| |
| #define SREAL_SIGN(v) (v < 0 ? -1: 1) |
| #define SREAL_ABS(v) (v < 0 ? -v: v) |
| |
| struct output_block; |
| struct lto_input_block; |
| |
| /* Structure for holding a simple real number. */ |
| class sreal |
| { |
| public: |
| /* Construct an uninitialized sreal. */ |
| sreal () : m_sig (-1), m_exp (-1) {} |
| |
| /* Construct a sreal. */ |
| sreal (int64_t sig, int exp = 0) |
| { |
| normalize (sig, exp); |
| } |
| |
| void dump (FILE *) const; |
| int64_t to_int () const; |
| double to_double () const; |
| void stream_out (struct output_block *); |
| static sreal stream_in (struct lto_input_block *); |
| sreal operator+ (const sreal &other) const; |
| sreal operator- (const sreal &other) const; |
| sreal operator* (const sreal &other) const; |
| sreal operator/ (const sreal &other) const; |
| |
| bool operator< (const sreal &other) const |
| { |
| if (m_exp == other.m_exp) |
| return m_sig < other.m_sig; |
| else |
| { |
| bool negative = m_sig < 0; |
| bool other_negative = other.m_sig < 0; |
| |
| if (negative != other_negative) |
| return negative > other_negative; |
| |
| bool r = m_exp < other.m_exp; |
| return negative ? !r : r; |
| } |
| } |
| |
| bool operator== (const sreal &other) const |
| { |
| return m_exp == other.m_exp && m_sig == other.m_sig; |
| } |
| |
| sreal operator- () const |
| { |
| sreal tmp = *this; |
| tmp.m_sig *= -1; |
| |
| return tmp; |
| } |
| |
| sreal shift (int s) const |
| { |
| /* Zero needs no shifting. */ |
| if (!m_sig) |
| return *this; |
| gcc_checking_assert (s <= SREAL_MAX_EXP); |
| gcc_checking_assert (s >= -SREAL_MAX_EXP); |
| |
| /* Overflows/drop to 0 could be handled gracefully, but hopefully we do not |
| need to do so. */ |
| gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP); |
| gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP); |
| |
| sreal tmp = *this; |
| tmp.m_exp += s; |
| |
| return tmp; |
| } |
| |
| /* Global minimum sreal can hold. */ |
| inline static sreal min () |
| { |
| sreal min; |
| /* This never needs normalization. */ |
| min.m_sig = -SREAL_MAX_SIG; |
| min.m_exp = SREAL_MAX_EXP; |
| return min; |
| } |
| |
| /* Global minimum sreal can hold. */ |
| inline static sreal max () |
| { |
| sreal max; |
| /* This never needs normalization. */ |
| max.m_sig = SREAL_MAX_SIG; |
| max.m_exp = SREAL_MAX_EXP; |
| return max; |
| } |
| |
| private: |
| inline void normalize (int64_t new_sig, signed int new_exp); |
| inline void normalize_up (int64_t new_sig, signed int new_exp); |
| inline void normalize_down (int64_t new_sig, signed int new_exp); |
| void shift_right (int amount); |
| static sreal signedless_plus (const sreal &a, const sreal &b, bool negative); |
| static sreal signedless_minus (const sreal &a, const sreal &b, bool negative); |
| |
| int32_t m_sig; /* Significant. */ |
| signed int m_exp; /* Exponent. */ |
| }; |
| |
| extern void debug (const sreal &ref); |
| extern void debug (const sreal *ptr); |
| |
| inline sreal &operator+= (sreal &a, const sreal &b) |
| { |
| return a = a + b; |
| } |
| |
| inline sreal &operator-= (sreal &a, const sreal &b) |
| { |
| return a = a - b; |
| } |
| |
| inline sreal &operator/= (sreal &a, const sreal &b) |
| { |
| return a = a / b; |
| } |
| |
| inline sreal &operator*= (sreal &a, const sreal &b) |
| { |
| return a = a * b; |
| } |
| |
| inline bool operator!= (const sreal &a, const sreal &b) |
| { |
| return !(a == b); |
| } |
| |
| inline bool operator> (const sreal &a, const sreal &b) |
| { |
| return !(a == b || a < b); |
| } |
| |
| inline bool operator<= (const sreal &a, const sreal &b) |
| { |
| return a < b || a == b; |
| } |
| |
| inline bool operator>= (const sreal &a, const sreal &b) |
| { |
| return a == b || a > b; |
| } |
| |
| inline sreal operator<< (const sreal &a, int exp) |
| { |
| return a.shift (exp); |
| } |
| |
| inline sreal operator>> (const sreal &a, int exp) |
| { |
| return a.shift (-exp); |
| } |
| |
| /* Make significant to be >= SREAL_MIN_SIG. |
| |
| Make this separate method so inliner can handle hot path better. */ |
| |
| inline void |
| sreal::normalize_up (int64_t new_sig, signed int new_exp) |
| { |
| unsigned HOST_WIDE_INT sig = absu_hwi (new_sig); |
| int shift = SREAL_PART_BITS - 2 - floor_log2 (sig); |
| |
| gcc_checking_assert (shift > 0); |
| sig <<= shift; |
| new_exp -= shift; |
| gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG); |
| |
| /* Check underflow. */ |
| if (new_exp < -SREAL_MAX_EXP) |
| { |
| new_exp = -SREAL_MAX_EXP; |
| sig = 0; |
| } |
| m_exp = new_exp; |
| if (SREAL_SIGN (new_sig) == -1) |
| m_sig = -sig; |
| else |
| m_sig = sig; |
| } |
| |
| /* Make significant to be <= SREAL_MAX_SIG. |
| |
| Make this separate method so inliner can handle hot path better. */ |
| |
| inline void |
| sreal::normalize_down (int64_t new_sig, signed int new_exp) |
| { |
| int last_bit; |
| unsigned HOST_WIDE_INT sig = absu_hwi (new_sig); |
| int shift = floor_log2 (sig) - SREAL_PART_BITS + 2; |
| |
| gcc_checking_assert (shift > 0); |
| last_bit = (sig >> (shift-1)) & 1; |
| sig >>= shift; |
| new_exp += shift; |
| gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG); |
| |
| /* Round the number. */ |
| sig += last_bit; |
| if (sig > SREAL_MAX_SIG) |
| { |
| sig >>= 1; |
| new_exp++; |
| } |
| |
| /* Check overflow. */ |
| if (new_exp > SREAL_MAX_EXP) |
| { |
| new_exp = SREAL_MAX_EXP; |
| sig = SREAL_MAX_SIG; |
| } |
| m_exp = new_exp; |
| if (SREAL_SIGN (new_sig) == -1) |
| m_sig = -sig; |
| else |
| m_sig = sig; |
| } |
| |
| /* Normalize *this; the hot path. */ |
| |
| inline void |
| sreal::normalize (int64_t new_sig, signed int new_exp) |
| { |
| unsigned HOST_WIDE_INT sig = absu_hwi (new_sig); |
| |
| if (sig == 0) |
| { |
| m_sig = 0; |
| m_exp = -SREAL_MAX_EXP; |
| } |
| else if (sig > SREAL_MAX_SIG) |
| normalize_down (new_sig, new_exp); |
| else if (sig < SREAL_MIN_SIG) |
| normalize_up (new_sig, new_exp); |
| else |
| { |
| m_sig = new_sig; |
| m_exp = new_exp; |
| } |
| } |
| |
| #endif |