1 /* d-longdouble.cc -- Software floating-point emulation for the frontend.
2    Copyright (C) 2006-2021 Free Software Foundation, Inc.
3 
4 GCC is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8 
9 GCC is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with GCC; see the file COPYING3.  If not see
16 <http://www.gnu.org/licenses/>.  */
17 
18 #include "config.h"
19 #include "system.h"
20 #include "coretypes.h"
21 
22 #include "dmd/mtype.h"
23 
24 #include "tree.h"
25 #include "fold-const.h"
26 #include "diagnostic.h"
27 #include "stor-layout.h"
28 
29 #include "d-tree.h"
30 #include "longdouble.h"
31 
32 
33 /* Truncate longdouble to the highest precision supported by target.  */
34 
35 longdouble
normalize(void)36 longdouble::normalize (void)
37 {
38   const machine_mode mode = TYPE_MODE (long_double_type_node);
39   real_convert (&this->rv (), mode, &this->rv ());
40   return *this;
41 }
42 
43 /* Assign a real_value to a longdouble type.  */
44 
45 void
set(real_value & d)46 longdouble::set (real_value &d)
47 {
48   real_convert (&this->rv (), TYPE_MODE (long_double_type_node), &d);
49 }
50 
51 /* Conversion routines between longdouble and integer types.  */
52 
53 void
set(int32_t d)54 longdouble::set (int32_t d)
55 {
56   real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, SIGNED);
57 }
58 
59 void
set(int64_t d)60 longdouble::set (int64_t d)
61 {
62   real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
63 		     SIGNED);
64 }
65 
66 int64_t
to_int(void) const67 longdouble::to_int (void) const
68 {
69   bool overflow;
70   wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
71   return wi.to_shwi ();
72 }
73 
74 /* Unsigned variants of the same conversion routines.  */
75 
76 void
set(uint32_t d)77 longdouble::set (uint32_t d)
78 {
79   real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, UNSIGNED);
80 }
81 
82 void
set(uint64_t d)83 longdouble::set (uint64_t d)
84 {
85   real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
86 		     UNSIGNED);
87 }
88 
89 uint64_t
to_uint(void) const90 longdouble::to_uint (void) const
91 {
92   bool overflow;
93   wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
94   return wi.to_uhwi ();
95 }
96 
97 /* For conversion between boolean, only need to check if is zero.  */
98 
99 void
set(bool d)100 longdouble::set (bool d)
101 {
102   this->rv () = (d == false) ? dconst0 : dconst1;
103 }
104 
105 bool
to_bool(void) const106 longdouble::to_bool (void) const
107 {
108   return this->rv ().cl != rvc_zero;
109 }
110 
111 /* Overload numeric operators for longdouble types.  */
112 
113 longdouble
add(const longdouble & r) const114 longdouble::add (const longdouble &r) const
115 {
116   longdouble x;
117   real_arithmetic (&x.rv (), PLUS_EXPR, &this->rv (), &r.rv ());
118   return x.normalize ();
119 }
120 
121 longdouble
sub(const longdouble & r) const122 longdouble::sub (const longdouble &r) const
123 {
124   longdouble x;
125   real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &r.rv ());
126   return x.normalize ();
127 }
128 
129 longdouble
mul(const longdouble & r) const130 longdouble::mul (const longdouble &r) const
131 {
132   longdouble x;
133   real_arithmetic (&x.rv (), MULT_EXPR, &this->rv (), &r.rv ());
134   return x.normalize ();
135 }
136 
137 longdouble
div(const longdouble & r) const138 longdouble::div (const longdouble &r) const
139 {
140   longdouble x;
141   real_arithmetic (&x.rv (), RDIV_EXPR, &this->rv (), &r.rv ());
142   return x.normalize ();
143 }
144 
145 longdouble
mod(const longdouble & r) const146 longdouble::mod (const longdouble &r) const
147 {
148   longdouble x;
149   real_value q;
150 
151   if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ()))
152     {
153       real_nan (&x.rv (), "", 1, TYPE_MODE (long_double_type_node));
154       return x;
155     }
156 
157   if (this->rv ().cl == rvc_zero)
158     return *this;
159 
160   if (REAL_VALUE_ISINF (r.rv ()))
161     return *this;
162 
163   /* Need to check for NaN?  */
164   real_arithmetic (&q, RDIV_EXPR, &this->rv (), &r.rv ());
165   real_arithmetic (&q, FIX_TRUNC_EXPR, &q, NULL);
166   real_arithmetic (&q, MULT_EXPR, &q, &r.rv ());
167   real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &q);
168 
169   return x.normalize ();
170 }
171 
172 longdouble
neg(void) const173 longdouble::neg (void) const
174 {
175   longdouble x;
176   real_arithmetic (&x.rv (), NEGATE_EXPR, &this->rv (), NULL);
177   return x.normalize ();
178 }
179 
180 /* Overload equality operators for longdouble types.  */
181 
182 int
cmp(const longdouble & r) const183 longdouble::cmp (const longdouble &r) const
184 {
185   if (real_compare (LT_EXPR, &this->rv (), &r.rv ()))
186     return -1;
187 
188   if (real_compare (GT_EXPR, &this->rv (), &r.rv ()))
189     return 1;
190 
191   return 0;
192 }
193 
194 int
equals(const longdouble & r) const195 longdouble::equals (const longdouble &r) const
196 {
197   return real_compare (EQ_EXPR, &this->rv (), &r.rv ());
198 }
199