ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
fp_functions.cpp
Go to the documentation of this file.
1 // Copyright (C) 2017, MINRES Technologies GmbH
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 // POSSIBILITY OF SUCH DAMAGE.
30 //
31 // Contributors:
32 // eyck@minres.com - initial API and implementation
34 extern "C" {
35 #include "softfloat_orig.h"
36 #include "internals.h"
37 #include "specialize.h"
38 #include "libsoftfloat.h"
39 }
40 #include <limits>
41 
42 const uint8_t rmm_map[] = {
43  softfloat_round_near_even /*RNE*/,
44  softfloat_round_minMag/*RTZ*/,
45  softfloat_round_min/*RDN*/,
46  softfloat_round_max/*RUP?*/,
47  softfloat_round_near_maxMag /*RMM*/,
48  softfloat_round_max/*RTZ*/,
49  softfloat_round_max/*RTZ*/,
50  softfloat_round_max/*RTZ*/,
51 };
52 
53 const uint32_t quiet_nan32=0x7fC00000;
54 extern "C" {
56  return softfloat_exceptionFlags&0x1f;
57 }
58 
60  float32_t v1f{v1},v2f{v2};
61  softfloat_roundingMode=rmm_map[mode&0x7];
62  softfloat_exceptionFlags=0;
63  float32_t r =f32_add(v1f, v2f);
64  return r.v;
65 }
66 
68  float32_t v1f{v1},v2f{v2};
69  softfloat_roundingMode=rmm_map[mode&0x7];
70  softfloat_exceptionFlags=0;
71  float32_t r=f32_sub(v1f, v2f);
72  return r.v;
73 }
74 
76  float32_t v1f{v1},v2f{v2};
77  softfloat_roundingMode=rmm_map[mode&0x7];
78  softfloat_exceptionFlags=0;
79  float32_t r=f32_mul(v1f, v2f);
80  return r.v;
81 }
82 
84  float32_t v1f{v1},v2f{v2};
85  softfloat_roundingMode=rmm_map[mode&0x7];
86  softfloat_exceptionFlags=0;
87  float32_t r=f32_div(v1f, v2f);
88  return r.v;
89 }
90 
92  float32_t v1f{v1};
93  softfloat_roundingMode=rmm_map[mode&0x7];
94  softfloat_exceptionFlags=0;
95  float32_t r=f32_sqrt(v1f);
96  return r.v;
97 }
98 
100  float32_t v1f{v1},v2f{v2};
101  softfloat_exceptionFlags=0;
102  bool nan = (v1&defaultNaNF32UI)==quiet_nan32 || (v2&defaultNaNF32UI)==quiet_nan32;
103  bool snan = softfloat_isSigNaNF32UI(v1) || softfloat_isSigNaNF32UI(v2);
104  switch(op){
105  case 0:
106  if(nan | snan){
107  if(snan) softfloat_raiseFlags(softfloat_flag_invalid);
108  return 0;
109  } else
110  return f32_eq(v1f,v2f )?1:0;
111  case 1:
112  if(nan | snan){
113  softfloat_raiseFlags(softfloat_flag_invalid);
114  return 0;
115  } else
116  return f32_le(v1f,v2f )?1:0;
117  case 2:
118  if(nan | snan){
119  softfloat_raiseFlags(softfloat_flag_invalid);
120  return 0;
121  } else
122  return f32_lt(v1f,v2f )?1:0;
123  default:
124  break;
125  }
126  return -1;
127 }
128 
130  float32_t v1f{v1};
131  softfloat_exceptionFlags=0;
132  float32_t r;
133  switch(op){
134  case 0:{ //w->s, fp to int32
135  uint_fast32_t res = f32_to_i32(v1f,rmm_map[mode&0x7],true);
136  return (uint32_t)res;
137  }
138  case 1:{ //wu->s
139  uint_fast32_t res = f32_to_ui32(v1f,rmm_map[mode&0x7],true);
140  return (uint32_t)res;
141  }
142  case 2: //s->w
143  r=i32_to_f32(v1);
144  return r.v;
145  case 3: //s->wu
146  r=ui32_to_f32(v1);
147  return r.v;
148  }
149  return 0;
150 }
151 
153  // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
154  softfloat_roundingMode=rmm_map[mode&0x7];
155  softfloat_exceptionFlags=0;
156  float32_t res = softfloat_mulAddF32(v1, v2, v3, op&0x1);
157  if(op>1) res.v ^= 1ULL<<31;
158  return res.v;
159 }
160 
162  softfloat_exceptionFlags = 0;
163  bool v1_nan = (v1 & defaultNaNF32UI) == defaultNaNF32UI;
164  bool v2_nan = (v2 & defaultNaNF32UI) == defaultNaNF32UI;
165  bool v1_snan = softfloat_isSigNaNF32UI(v1);
166  bool v2_snan = softfloat_isSigNaNF32UI(v2);
167  if (v1_snan || v2_snan) softfloat_raiseFlags(softfloat_flag_invalid);
168  if (v1_nan || v1_snan)
169  return (v2_nan || v2_snan) ? defaultNaNF32UI : v2;
170  else
171  if (v2_nan || v2_snan)
172  return v1;
173  else {
174  if ((v1 & 0x7fffffff) == 0 && (v2 & 0x7fffffff) == 0) {
175  return op == 0 ? ((v1 & 0x80000000) ? v1 : v2) : ((v1 & 0x80000000) ? v2 : v1);
176  } else {
177  float32_t v1f{ v1 }, v2f{ v2 };
178  return op == 0 ? (f32_lt(v1f, v2f) ? v1 : v2) : (f32_lt(v1f, v2f) ? v2 : v1);
179  }
180  }
181 }
182 
184 
185  float32_t a{v1};
186  union ui32_f32 uA;
187  uint_fast32_t uiA;
188 
189  uA.f = a;
190  uiA = uA.ui;
191 
192  uint_fast16_t infOrNaN = expF32UI( uiA ) == 0xFF;
193  uint_fast16_t subnormalOrZero = expF32UI( uiA ) == 0;
194  bool sign = signF32UI( uiA );
195  bool fracZero = fracF32UI( uiA ) == 0;
196  bool isNaN = isNaNF32UI( uiA );
197  bool isSNaN = softfloat_isSigNaNF32UI( uiA );
198 
199  return
200  ( sign && infOrNaN && fracZero ) << 0 |
201  ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
202  ( sign && subnormalOrZero && !fracZero ) << 2 |
203  ( sign && subnormalOrZero && fracZero ) << 3 |
204  ( !sign && infOrNaN && fracZero ) << 7 |
205  ( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
206  ( !sign && subnormalOrZero && !fracZero ) << 5 |
207  ( !sign && subnormalOrZero && fracZero ) << 4 |
208  ( isNaN && isSNaN ) << 8 |
209  ( isNaN && !isSNaN ) << 9;
210 }
211 
213  softfloat_roundingMode=rmm_map[mode&0x7];
214  bool nan = (v1 & defaultNaNF64UI)==defaultNaNF64UI;
215  if(nan){
216  return defaultNaNF32UI;
217  } else {
218  float32_t res = f64_to_f32(float64_t{v1});
219  return res.v;
220  }
221 }
222 
224  bool nan = (v1 & defaultNaNF32UI)==defaultNaNF32UI;
225  if(nan){
226  return defaultNaNF64UI;
227  } else {
228  softfloat_roundingMode=rmm_map[mode&0x7];
229  float64_t res = f32_to_f64(float32_t{v1});
230  return res.v;
231  }
232 }
233 
235  bool nan = (v1&defaultNaNF32UI)==quiet_nan32;
236  bool snan = softfloat_isSigNaNF32UI(v1);
237  float64_t v1f{v1},v2f{v2};
238  softfloat_roundingMode=rmm_map[mode&0x7];
239  softfloat_exceptionFlags=0;
240  float64_t r =f64_add(v1f, v2f);
241  (void) nan; //TODO: should there really be no check with nan/snan?
242  (void) snan;
243  return r.v;
244 }
245 
247  float64_t v1f{v1},v2f{v2};
248  softfloat_roundingMode=rmm_map[mode&0x7];
249  softfloat_exceptionFlags=0;
250  float64_t r=f64_sub(v1f, v2f);
251  return r.v;
252 }
253 
255  float64_t v1f{v1},v2f{v2};
256  softfloat_roundingMode=rmm_map[mode&0x7];
257  softfloat_exceptionFlags=0;
258  float64_t r=f64_mul(v1f, v2f);
259  return r.v;
260 }
261 
263  float64_t v1f{v1},v2f{v2};
264  softfloat_roundingMode=rmm_map[mode&0x7];
265  softfloat_exceptionFlags=0;
266  float64_t r=f64_div(v1f, v2f);
267  return r.v;
268 }
269 
271  float64_t v1f{v1};
272  softfloat_roundingMode=rmm_map[mode&0x7];
273  softfloat_exceptionFlags=0;
274  float64_t r=f64_sqrt(v1f);
275  return r.v;
276 }
277 
279  float64_t v1f{v1},v2f{v2};
280  softfloat_exceptionFlags=0;
281  bool nan = (v1&defaultNaNF64UI)==quiet_nan32 || (v2&defaultNaNF64UI)==quiet_nan32;
282  bool snan = softfloat_isSigNaNF64UI(v1) || softfloat_isSigNaNF64UI(v2);
283  switch(op){
284  case 0:
285  if(nan | snan){
286  if(snan) softfloat_raiseFlags(softfloat_flag_invalid);
287  return 0;
288  } else
289  return f64_eq(v1f,v2f )?1:0;
290  case 1:
291  if(nan | snan){
292  softfloat_raiseFlags(softfloat_flag_invalid);
293  return 0;
294  } else
295  return f64_le(v1f,v2f )?1:0;
296  case 2:
297  if(nan | snan){
298  softfloat_raiseFlags(softfloat_flag_invalid);
299  return 0;
300  } else
301  return f64_lt(v1f,v2f )?1:0;
302  default:
303  break;
304  }
305  return -1;
306 }
307 
309  float64_t v1f{v1};
310  softfloat_exceptionFlags=0;
311  float64_t r;
312  switch(op){
313  case 0:{ //l->d, fp to int32
314  int64_t res = f64_to_i64(v1f,rmm_map[mode&0x7],true);
315  return (uint64_t)res;
316  }
317  case 1:{ //lu->s
318  uint64_t res = f64_to_ui64(v1f,rmm_map[mode&0x7],true);
319  return res;
320  }
321  case 2: //s->l
322  r=i64_to_f64(v1);
323  return r.v;
324  case 3: //s->lu
325  r=ui64_to_f64(v1);
326  return r.v;
327  }
328  return 0;
329 }
330 
332  // op should be {softfloat_mulAdd_subProd(2), softfloat_mulAdd_subC(1)}
333  softfloat_roundingMode=rmm_map[mode&0x7];
334  softfloat_exceptionFlags=0;
335  float64_t res = softfloat_mulAddF64(v1, v2, v3, op&0x1);
336  if(op>1) res.v ^= 1ULL<<63;
337  return res.v;
338 }
339 
341  softfloat_exceptionFlags = 0;
342  bool v1_nan = (v1 & defaultNaNF64UI) == defaultNaNF64UI;
343  bool v2_nan = (v2 & defaultNaNF64UI) == defaultNaNF64UI;
344  bool v1_snan = softfloat_isSigNaNF64UI(v1);
345  bool v2_snan = softfloat_isSigNaNF64UI(v2);
346  if (v1_snan || v2_snan) softfloat_raiseFlags(softfloat_flag_invalid);
347  if (v1_nan || v1_snan)
348  return (v2_nan || v2_snan) ? defaultNaNF64UI : v2;
349  else
350  if (v2_nan || v2_snan)
351  return v1;
352  else {
353  if ((v1 & std::numeric_limits<int64_t>::max()) == 0 && (v2 & std::numeric_limits<int64_t>::max()) == 0) {
354  return op == 0 ?
355  ((v1 & std::numeric_limits<int64_t>::min()) ? v1 : v2) :
356  ((v1 & std::numeric_limits<int64_t>::min()) ? v2 : v1);
357  } else {
358  float64_t v1f{ v1 }, v2f{ v2 };
359  return op == 0 ?
360  (f64_lt(v1f, v2f) ? v1 : v2) :
361  (f64_lt(v1f, v2f) ? v2 : v1);
362  }
363  }
364 }
365 
367 
368  float64_t a{v1};
369  union ui64_f64 uA;
370  uint_fast64_t uiA;
371 
372  uA.f = a;
373  uiA = uA.ui;
374 
375  uint_fast16_t infOrNaN = expF64UI( uiA ) == 0x7FF;
376  uint_fast16_t subnormalOrZero = expF64UI( uiA ) == 0;
377  bool sign = signF64UI( uiA );
378  bool fracZero = fracF64UI( uiA ) == 0;
379  bool isNaN = isNaNF64UI( uiA );
380  bool isSNaN = softfloat_isSigNaNF64UI( uiA );
381 
382  return
383  ( sign && infOrNaN && fracZero ) << 0 |
384  ( sign && !infOrNaN && !subnormalOrZero ) << 1 |
385  ( sign && subnormalOrZero && !fracZero ) << 2 |
386  ( sign && subnormalOrZero && fracZero ) << 3 |
387  ( !sign && infOrNaN && fracZero ) << 7 |
388  ( !sign && !infOrNaN && !subnormalOrZero ) << 6 |
389  ( !sign && subnormalOrZero && !fracZero ) << 5 |
390  ( !sign && subnormalOrZero && fracZero ) << 4 |
391  ( isNaN && isSNaN ) << 8 |
392  ( isNaN && !isSNaN ) << 9;
393 }
394 
396  float32_t v1f{v1};
397  softfloat_exceptionFlags=0;
398  float64_t r;
399  switch(op){
400  case 0: //l->s, fp to int32
401  return f32_to_i64(v1f,rmm_map[mode&0x7],true);
402  case 1: //wu->s
403  return f32_to_ui64(v1f,rmm_map[mode&0x7],true);
404  case 2: //s->w
405  r=i32_to_f64(v1);
406  return r.v;
407  case 3: //s->wu
408  r=ui32_to_f64(v1);
409  return r.v;
410  }
411  return 0;
412 }
413 
415  softfloat_exceptionFlags=0;
416  float32_t r;
417  switch(op){
418  case 0:{ //wu->s
419  int32_t r=f64_to_i32(float64_t{v1}, rmm_map[mode&0x7],true);
420  return r;
421  }
422  case 1:{ //wu->s
423  uint32_t r=f64_to_ui32(float64_t{v1}, rmm_map[mode&0x7],true);
424  return r;
425  }
426  case 2: //l->s, fp to int32
427  r=i64_to_f32(v1);
428  return r.v;
429  case 3: //wu->s
430  r=ui64_to_f32(v1);
431  return r.v;
432  }
433  return 0;
434 }
435 
438  if((v & mask) != mask)
439  return 0x7fc00000;
440  else
442 }
443 }
__DEVICE__ int min(int __a, int __b)
__DEVICE__ int max(int __a, int __b)
__DEVICE__ double nan(const char *)
do v
Definition: arm_acle.h:76
static __inline__ uint32_t
Definition: arm_cde.h:25
static __inline__ uint64_t
Definition: arm_cde.h:31
static __inline__ int32_t
Definition: arm_mve.h:51
static __inline__ uint8_t
Definition: arm_mve.h:323
uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op)
uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode)
uint64_t fdiv_d(uint64_t v1, uint64_t v2, uint8_t mode)
uint32_t fclass_s(uint32_t v1)
const uint8_t rmm_map[]
uint32_t fmadd_s(uint32_t v1, uint32_t v2, uint32_t v3, uint32_t op, uint8_t mode)
uint64_t fcvt_d(uint64_t v1, uint32_t op, uint8_t mode)
uint32_t fget_flags()
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode)
uint64_t fconv_f2d(uint32_t v1, uint8_t mode)
uint32_t fdiv_s(uint32_t v1, uint32_t v2, uint8_t mode)
uint32_t fconv_d2f(uint64_t v1, uint8_t mode)
uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode)
uint32_t unbox_s(uint64_t v)
uint32_t fcvt_s(uint32_t v1, uint32_t op, uint8_t mode)
uint32_t fsqrt_s(uint32_t v1, uint8_t mode)
const uint32_t quiet_nan32
uint64_t fclass_d(uint64_t v1)
uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode)
uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode)
uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode)
uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op)
uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode)
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op)
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op)
uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode)
uint64_t fsqrt_d(uint64_t v1, uint8_t mode)
uint64_t fmadd_d(uint64_t v1, uint64_t v2, uint64_t v3, uint32_t op, uint8_t mode)
float __ovld __cnfn sign(float x)
Returns 1.0 if x > 0, -0.0 if x = -0.0, +0.0 if x = +0.0, or -1.0 if x < 0.