1 /* d-longdouble.cc -- Software floating-point emulation for the frontend.
2    Copyright (C) 2006-2020 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 /* Constant real values 0, 1, -1 and 0.5.  */
34 real_t CTFloat::zero;
35 real_t CTFloat::one;
36 real_t CTFloat::minusone;
37 real_t CTFloat::half;
38 
39 /* Truncate longdouble to the highest precision supported by target.  */
40 
41 longdouble
normalize(void)42 longdouble::normalize (void)
43 {
44   const machine_mode mode = TYPE_MODE (long_double_type_node);
45   real_convert (&this->rv (), mode, &this->rv ());
46   return *this;
47 }
48 
49 /* Assign a real_value to a longdouble type.  */
50 
51 void
set(real_value & d)52 longdouble::set (real_value& d)
53 {
54   real_convert (&this->rv (), TYPE_MODE (long_double_type_node), &d);
55 }
56 
57 /* Conversion routines between longdouble and integer types.  */
58 
59 void
set(int32_t d)60 longdouble::set (int32_t d)
61 {
62   real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, SIGNED);
63 }
64 
65 void
set(int64_t d)66 longdouble::set (int64_t d)
67 {
68   real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
69 		     SIGNED);
70 }
71 
72 int64_t
to_int(void) const73 longdouble::to_int (void) const
74 {
75   bool overflow;
76   wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
77   return wi.to_shwi ();
78 }
79 
80 /* Unsigned variants of the same conversion routines.  */
81 
82 void
set(uint32_t d)83 longdouble::set (uint32_t d)
84 {
85   real_from_integer (&this->rv (), TYPE_MODE (double_type_node), d, UNSIGNED);
86 }
87 
88 void
set(uint64_t d)89 longdouble::set (uint64_t d)
90 {
91   real_from_integer (&this->rv (), TYPE_MODE (long_double_type_node), d,
92 		     UNSIGNED);
93 }
94 
95 uint64_t
to_uint(void) const96 longdouble::to_uint (void) const
97 {
98   bool overflow;
99   wide_int wi = real_to_integer (&this->rv (), &overflow, 64);
100   return wi.to_uhwi ();
101 }
102 
103 /* For conversion between boolean, only need to check if is zero.  */
104 
105 void
set(bool d)106 longdouble::set (bool d)
107 {
108   this->rv () = (d == false) ? dconst0 : dconst1;
109 }
110 
111 bool
to_bool(void) const112 longdouble::to_bool (void) const
113 {
114   return this->rv ().cl != rvc_zero;
115 }
116 
117 /* Overload numeric operators for longdouble types.  */
118 
119 longdouble
add(const longdouble & r) const120 longdouble::add (const longdouble& r) const
121 {
122   longdouble x;
123   real_arithmetic (&x.rv (), PLUS_EXPR, &this->rv (), &r.rv ());
124   return x.normalize ();
125 }
126 
127 longdouble
sub(const longdouble & r) const128 longdouble::sub (const longdouble& r) const
129 {
130   longdouble x;
131   real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &r.rv ());
132   return x.normalize ();
133 }
134 
135 longdouble
mul(const longdouble & r) const136 longdouble::mul (const longdouble& r) const
137 {
138   longdouble x;
139   real_arithmetic (&x.rv (), MULT_EXPR, &this->rv (), &r.rv ());
140   return x.normalize ();
141 }
142 
143 longdouble
div(const longdouble & r) const144 longdouble::div (const longdouble& r) const
145 {
146   longdouble x;
147   real_arithmetic (&x.rv (), RDIV_EXPR, &this->rv (), &r.rv ());
148   return x.normalize ();
149 }
150 
151 longdouble
mod(const longdouble & r) const152 longdouble::mod (const longdouble& r) const
153 {
154   longdouble x;
155   real_value q;
156 
157   if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ()))
158     {
159       real_nan (&x.rv (), "", 1, TYPE_MODE (long_double_type_node));
160       return x;
161     }
162 
163   if (this->rv ().cl == rvc_zero)
164     return *this;
165 
166   if (REAL_VALUE_ISINF (r.rv ()))
167     return *this;
168 
169   /* Need to check for NaN?  */
170   real_arithmetic (&q, RDIV_EXPR, &this->rv (), &r.rv ());
171   real_arithmetic (&q, FIX_TRUNC_EXPR, &q, NULL);
172   real_arithmetic (&q, MULT_EXPR, &q, &r.rv ());
173   real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &q);
174 
175   return x.normalize ();
176 }
177 
178 longdouble
neg(void) const179 longdouble::neg (void) const
180 {
181   longdouble x;
182   real_arithmetic (&x.rv (), NEGATE_EXPR, &this->rv (), NULL);
183   return x.normalize ();
184 }
185 
186 /* Overload equality operators for longdouble types.  */
187 
188 int
cmp(const longdouble & r) const189 longdouble::cmp (const longdouble& r) const
190 {
191   if (real_compare (LT_EXPR, &this->rv (), &r.rv ()))
192     return -1;
193 
194   if (real_compare (GT_EXPR, &this->rv (), &r.rv ()))
195     return 1;
196 
197   return 0;
198 }
199 
200 int
equals(const longdouble & r) const201 longdouble::equals (const longdouble& r) const
202 {
203   return real_compare (EQ_EXPR, &this->rv (), &r.rv ());
204 }
205