(root)/
gcc-13.2.0/
gcc/
sreal.h
       1  /* Definitions for simple data type for real numbers.
       2     Copyright (C) 2002-2023 Free Software Foundation, Inc.
       3  
       4  This file is part of GCC.
       5  
       6  GCC is free software; you can redistribute it and/or modify it under
       7  the terms of the GNU General Public License as published by the Free
       8  Software Foundation; either version 3, or (at your option) any later
       9  version.
      10  
      11  GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12  WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  for more details.
      15  
      16  You should have received a copy of the GNU General Public License
      17  along with GCC; see the file COPYING3.  If not see
      18  <http://www.gnu.org/licenses/>.  */
      19  
      20  #ifndef GCC_SREAL_H
      21  #define GCC_SREAL_H
      22  
      23  #define SREAL_PART_BITS 31
      24  
      25  #define UINT64_BITS	64
      26  
      27  #define SREAL_MIN_SIG ((int64_t) 1 << (SREAL_PART_BITS - 2))
      28  #define SREAL_MAX_SIG (((int64_t) 1 << (SREAL_PART_BITS - 1)) - 1)
      29  #define SREAL_MAX_EXP (INT_MAX / 4)
      30  
      31  #define SREAL_BITS SREAL_PART_BITS
      32  
      33  #define SREAL_SIGN(v) (v < 0 ? -1: 1)
      34  #define SREAL_ABS(v) (v < 0 ? -v: v)
      35  
      36  struct output_block;
      37  class lto_input_block;
      38  
      39  /* Structure for holding a simple real number.  */
      40  class sreal
      41  {
      42  public:
      43    /* Construct an uninitialized sreal.  */
      44    sreal () : m_sig (-1), m_exp (-1) {}
      45  
      46    /* Construct a sreal.  */
      47    sreal (int64_t sig, int exp = 0)
      48    {
      49      normalize (sig, exp);
      50    }
      51  
      52    void dump (FILE *) const;
      53    int64_t to_int () const;
      54    double to_double () const;
      55    void stream_out (struct output_block *);
      56    static sreal stream_in (class lto_input_block *);
      57    sreal operator+ (const sreal &other) const;
      58    sreal operator- (const sreal &other) const;
      59    sreal operator* (const sreal &other) const;
      60    sreal operator/ (const sreal &other) const;
      61  
      62    bool operator< (const sreal &other) const
      63    {
      64      if (m_exp == other.m_exp)
      65        return m_sig < other.m_sig;
      66      else
      67      {
      68        bool negative = m_sig < 0;
      69        bool other_negative = other.m_sig < 0;
      70  
      71        if (negative != other_negative)
      72          return negative > other_negative;
      73  
      74        bool r = m_exp < other.m_exp;
      75        return negative ? !r : r;
      76      }
      77    }
      78  
      79    bool operator== (const sreal &other) const
      80    {
      81      return m_exp == other.m_exp && m_sig == other.m_sig;
      82    }
      83  
      84    sreal operator- () const
      85    {
      86      sreal tmp = *this;
      87      tmp.m_sig *= -1;
      88  
      89      return tmp;
      90    }
      91  
      92    sreal shift (int s) const
      93    {
      94      /* Zero needs no shifting.  */
      95      if (!m_sig)
      96        return *this;
      97      gcc_checking_assert (s <= SREAL_MAX_EXP);
      98      gcc_checking_assert (s >= -SREAL_MAX_EXP);
      99  
     100      /* Overflows/drop to 0 could be handled gracefully, but hopefully we do not
     101         need to do so.  */
     102      gcc_checking_assert (m_exp + s <= SREAL_MAX_EXP);
     103      gcc_checking_assert (m_exp + s >= -SREAL_MAX_EXP);
     104  
     105      sreal tmp = *this;
     106      tmp.m_exp += s;
     107  
     108      return tmp;
     109    }
     110  
     111    /* Global minimum sreal can hold.  */
     112    inline static sreal min ()
     113    {
     114      sreal min;
     115      /* This never needs normalization.  */
     116      min.m_sig = -SREAL_MAX_SIG;
     117      min.m_exp = SREAL_MAX_EXP;
     118      return min;
     119    }
     120  
     121    /* Global minimum sreal can hold.  */
     122    inline static sreal max ()
     123    {
     124      sreal max;
     125      /* This never needs normalization.  */
     126      max.m_sig = SREAL_MAX_SIG;
     127      max.m_exp = SREAL_MAX_EXP;
     128      return max;
     129    }
     130  
     131  private:
     132    inline void normalize (int64_t new_sig, signed int new_exp);
     133    inline void normalize_up (int64_t new_sig, signed int new_exp);
     134    inline void normalize_down (int64_t new_sig, signed int new_exp);
     135    void shift_right (int amount);
     136    static sreal signedless_plus (const sreal &a, const sreal &b, bool negative);
     137    static sreal signedless_minus (const sreal &a, const sreal &b, bool negative);
     138  
     139    int32_t m_sig;			/* Significant.  */
     140    signed int m_exp;			/* Exponent.  */
     141  };
     142  
     143  extern void debug (const sreal &ref);
     144  extern void debug (const sreal *ptr);
     145  
     146  inline sreal &operator+= (sreal &a, const sreal &b)
     147  {
     148    return a = a + b;
     149  }
     150  
     151  inline sreal &operator-= (sreal &a, const sreal &b)
     152  {
     153    return a = a - b;
     154  }
     155  
     156  inline sreal &operator/= (sreal &a, const sreal &b)
     157  {
     158    return a = a / b;
     159  }
     160  
     161  inline sreal &operator*= (sreal &a, const sreal &b)
     162  {
     163    return a = a  * b;
     164  }
     165  
     166  inline bool operator!= (const sreal &a, const sreal &b)
     167  {
     168    return !(a == b);
     169  }
     170  
     171  inline bool operator> (const sreal &a, const sreal &b)
     172  {
     173    return !(a == b || a < b);
     174  }
     175  
     176  inline bool operator<= (const sreal &a, const sreal &b)
     177  {
     178    return a < b || a == b;
     179  }
     180  
     181  inline bool operator>= (const sreal &a, const sreal &b)
     182  {
     183    return a == b || a > b;
     184  }
     185  
     186  inline sreal operator<< (const sreal &a, int exp)
     187  {
     188    return a.shift (exp);
     189  }
     190  
     191  inline sreal operator>> (const sreal &a, int exp)
     192  {
     193    return a.shift (-exp);
     194  }
     195  
     196  /* Make significant to be >= SREAL_MIN_SIG.
     197  
     198     Make this separate method so inliner can handle hot path better.  */
     199  
     200  inline void
     201  sreal::normalize_up (int64_t new_sig, signed int new_exp)
     202  {
     203    unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
     204    int shift = SREAL_PART_BITS - 2 - floor_log2 (sig);
     205  
     206    gcc_checking_assert (shift > 0);
     207    sig <<= shift;
     208    new_exp -= shift;
     209    gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
     210  
     211    /* Check underflow.  */
     212    if (new_exp < -SREAL_MAX_EXP)
     213      {
     214        new_exp = -SREAL_MAX_EXP;
     215        sig = 0;
     216      }
     217    m_exp = new_exp;
     218    if (SREAL_SIGN (new_sig) == -1)
     219      m_sig = -sig;
     220    else
     221      m_sig = sig;
     222  }
     223  
     224  /* Make significant to be <= SREAL_MAX_SIG.
     225  
     226     Make this separate method so inliner can handle hot path better.  */
     227  
     228  inline void
     229  sreal::normalize_down (int64_t new_sig, signed int new_exp)
     230  {
     231    int last_bit;
     232    unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
     233    int shift = floor_log2 (sig) - SREAL_PART_BITS + 2;
     234  
     235    gcc_checking_assert (shift > 0);
     236    last_bit = (sig >> (shift-1)) & 1;
     237    sig >>= shift;
     238    new_exp += shift;
     239    gcc_checking_assert (sig <= SREAL_MAX_SIG && sig >= SREAL_MIN_SIG);
     240  
     241    /* Round the number.  */
     242    sig += last_bit;
     243    if (sig > SREAL_MAX_SIG)
     244      {
     245        sig >>= 1;
     246        new_exp++;
     247      }
     248  
     249    /* Check overflow.  */
     250    if (new_exp > SREAL_MAX_EXP)
     251      {
     252        new_exp = SREAL_MAX_EXP;
     253        sig = SREAL_MAX_SIG;
     254      }
     255    m_exp = new_exp;
     256    if (SREAL_SIGN (new_sig) == -1)
     257      m_sig = -sig;
     258    else
     259      m_sig = sig;
     260  }
     261  
     262  /* Normalize *this; the hot path.  */
     263  
     264  inline void
     265  sreal::normalize (int64_t new_sig, signed int new_exp)
     266  {
     267    unsigned HOST_WIDE_INT sig = absu_hwi (new_sig);
     268  
     269    if (sig == 0)
     270      {
     271        m_sig = 0;
     272        m_exp = -SREAL_MAX_EXP;
     273      }
     274    else if (sig > SREAL_MAX_SIG)
     275      normalize_down (new_sig, new_exp);
     276    else if (sig < SREAL_MIN_SIG)
     277      normalize_up (new_sig, new_exp);
     278    else
     279      {
     280        m_sig = new_sig;
     281        m_exp = new_exp;
     282      }
     283  }
     284  
     285  #endif