GCC Code Coverage Report
Directory: . Exec Total Coverage
File: build-coverage/deps/include/symfpu/core/unpackedFloat.h Lines: 139 139 100.0 %
Date: 2021-08-14 Branches: 266 485 54.8 %

Line Exec Source
1
/*
2
** Copyright (C) 2018 Martin Brain
3
**
4
** See the file LICENSE for licensing information.
5
*/
6
7
/*
8
** unpackedFloat.h
9
**
10
** Martin Brain
11
** martin.brain@cs.ox.ac.uk
12
** 03/06/14
13
**
14
** The working representation of a floating-point number.  This is
15
** from the packed representation in a few ways:
16
**
17
**  1. Explicit flags for NaN, Inf and Zero.
18
**  2. Significand is biased.
19
**  3. Hidden bit is explicit.
20
**  4. Subnormals are normalised.
21
**
22
** This makes numbers more uniform and makes it easier to implement
23
** compact and efficient algorithms.
24
*/
25
26
#include "symfpu/utils/common.h"
27
#include "symfpu/utils/properties.h"
28
#include "symfpu/utils/numberOfRoundingModes.h"
29
30
#include "symfpu/core/ite.h"
31
#include "symfpu/core/operations.h"
32
33
// For debugging only
34
#include <iostream>
35
36
#ifndef SYMFPU_UNPACKED_FLOAT
37
#define SYMFPU_UNPACKED_FLOAT
38
39
namespace symfpu {
40
41
  template<class t>
42
36174
    class unpackedFloat {
43
  public :
44
    // Typedef the names from the traits for convenience
45
    typedef typename t::bwt bwt;
46
    typedef typename t::fpt fpt;
47
    typedef typename t::prop prop;
48
    typedef typename t::sbv sbv;
49
    typedef typename t::ubv ubv;
50
51
52
  protected :
53
    // TODO : protect these again
54
  public :
55
    prop nan;
56
    prop inf;
57
    prop zero;
58
59
    prop sign;
60
    sbv exponent;
61
    ubv significand;
62
  protected :
63
64
    // It is possible, but hopefully as difficult as possible to create,
65
    // via the constructor an invalid unpacked float
66
67
    // A piecewise / literal constructor using fpclass
68
    enum fpclass { FPCLASS_NAN, FPCLASS_INF, FPCLASS_ZERO, FPCLASS_NUMBER };
69
70
7547
    unpackedFloat (const fpclass c, const prop &s, const sbv &exp, const ubv &signif) :
71
21405
      nan(c == FPCLASS_NAN), inf(c == FPCLASS_INF), zero(c == FPCLASS_ZERO),
72
21817
      sign(s), exponent(exp), significand(signif)
73
7547
      {}
74
75
76
    // Should only be used by ite
77
    friend ite<prop, unpackedFloat<t> >;
78
79
    // TODO : See above -- this should only be used by ite
80
  public :
81
14413
    unpackedFloat (const prop &iteNaN, const prop &iteInf, const prop &iteZero,
82
		   const prop &iteSign, const sbv &iteExponent, const ubv &iteSignificand) :
83
      nan(iteNaN), inf(iteInf), zero(iteZero),
84
14413
      sign(iteSign), exponent(iteExponent), significand(iteSignificand)
85
14413
      {}
86
  private :
87
88
    // Used for special values
89
    // However this will also be passed through the operations, thus
90
    // if it is also a valid normal number then it will make proving
91
    // invariants easier.  In this case it is the value 1.0.
92
93
31797
    static sbv defaultExponent(const fpt &fmt) {
94
31797
      return sbv::zero(unpackedFloat<t>::exponentWidth(fmt));
95
    }
96
97
30778
    static ubv defaultSignificand(const fpt &fmt) {
98
30778
      bwt significandWidth = unpackedFloat<t>::significandWidth(fmt);
99
100
30778
      return ubv::one(significandWidth) << ubv(significandWidth, (significandWidth - 1));
101
    }
102
103
104
105
  public :
106
5400
    unpackedFloat (const prop &s, const sbv &exp, const ubv &signif) :
107
      nan(false), inf(false), zero(false),
108
5400
      sign(s), exponent(exp), significand(signif)
109
5400
      {}
110
111
    // An intermediate point in some operations is producing a value in an extended
112
    // format (for example, multiply produces an intermediate value with one extra exponent
113
    // bit and double the number of significand bits).  However the unpacked size of the
114
    // significand is larger than the bits given by the format.  This constructor does
115
    // the appropriate extension so that what is constructed is a valid unpacked float
116
    // in the given format.
117
1019
    unpackedFloat (const fpt &fmt, const prop &s, const sbv &exp, const ubv &signif) :
118
      nan(false), inf(false), zero(false),
119
1019
      sign(s), exponent(exp.matchWidth(defaultExponent(fmt))), significand(signif)
120
1019
      {}
121
122
6102
    unpackedFloat (const unpackedFloat<t> &old) :
123
15063
      nan(old.nan), inf(old.inf), zero(old.zero),
124
16144
      sign(old.sign), exponent(old.exponent), significand(old.significand)
125
6102
      {}
126
127
    // Copy and over-write sign
128
919
    unpackedFloat (const unpackedFloat<t> &old, const prop &s) :
129
2532
      nan(old.nan), inf(old.inf), zero(old.zero),
130
2607
      sign(ITE(old.nan, old.sign, s)), exponent(old.exponent), significand(old.significand)
131
919
      {}
132
133
    // Swap back-ends
134
      template <class s> friend class unpackedFloat;
135
136
    template <class s>
137
256
    unpackedFloat (const unpackedFloat<s> &old) :
138
768
      nan(old.nan), inf(old.inf), zero(old.zero),
139
1024
      sign(old.sign), exponent(old.exponent), significand(old.significand)
140
256
      {}
141
142
143
3475
    static unpackedFloat<t> makeZero(const fpt &fmt, const prop &s) {
144
3475
      return unpackedFloat<t>(FPCLASS_ZERO, s, defaultExponent(fmt), defaultSignificand(fmt));
145
    }
146
147
2525
    static unpackedFloat<t> makeInf(const fpt &fmt, const prop &s) {
148
2525
      return unpackedFloat<t>(FPCLASS_INF, s, defaultExponent(fmt), defaultSignificand(fmt));
149
    }
150
151
1547
    static unpackedFloat<t> makeNaN(const fpt &fmt) {
152
1547
      return unpackedFloat<t>(FPCLASS_NAN, false, defaultExponent(fmt), defaultSignificand(fmt));
153
    }
154
155
27915
    inline const prop & getNaN(void) const { return this->nan; }
156
22821
    inline const prop & getInf(void) const { return this->inf; }
157
24102
    inline const prop & getZero(void) const { return this->zero; }
158
31733
    inline const prop & getSign(void) const { return this->sign; }
159
17229
    inline const sbv & getExponent(void) const { return this->exponent; }
160
19826
    inline const ubv & getSignificand(void) const { return this->significand; }
161
162
    //    inline unpackedFloat<t> changeSign(const prop &newSign) {
163
    //      return unpackedFloat<t>(*this, newSign);
164
    //    }
165
166
167
168
169
    // Get the number of bits in the unpacked format corresponding to a
170
    // given packed format.  These are the unpacked counter-parts of
171
    //  format.exponentWidth() and format.significandWidth()
172
173
360409
    static bwt exponentWidth(const fpt &format) {
174
175
      // This calculation is a little more complex than you might think...
176
177
      // Note that there is one more exponent above 0 than there is
178
      // below.  This is the opposite of 2's compliment but this is not
179
      // a problem because the highest packed exponent corresponds to
180
      // inf and NaN and is thus does not need to be represented in the
181
      // unpacked format.
182
      // However we do need to increase it to allow subnormals (packed)
183
      // to be normalised.
184
185
      // The smallest exponent is:
186
      //  -2^(format.exponentWidth() - 1) - 2  -  (format.significandWidth() - 1)
187
      //
188
      // We need an unpacked exponent width u such that
189
      //  -2^(u-1) <= -2^(format.exponentWidth() - 1) - 2  -     (format.significandWidth() - 1)
190
      //           i.e.
191
      //   2^(u-1) >=  2^(format.exponentWidth() - 1)      +     (format.significandWidth() - 3)
192
193
360409
      bwt formatExponentWidth = format.exponentWidth();
194
360409
      bwt formatSignificandWidth = format.significandWidth();
195
196
360409
      if (formatSignificandWidth <= 3) {
197
	// Subnormals fit into the gap between minimum normal exponent and what is represenatble
198
	// using a signed number
199
1088
	return formatExponentWidth;
200
      }
201
202
359321
      bwt bitsNeededForSubnormals = bitsToRepresent(format.significandWidth() - 3);
203
359321
      if (bitsNeededForSubnormals < formatExponentWidth - 1) {
204
	// Significand is short compared to exponent range,
205
	// one extra bit should be sufficient
206
45470
	return formatExponentWidth + 1;
207
208
      } else {
209
	// Significand is long compared to exponent range
210
313851
	return bitsToRepresent((bwt(1) << (formatExponentWidth - 1)) + formatSignificandWidth - 3) + 1;
211
      }
212
    }
213
214
135756
    static bwt significandWidth(const fpt &format) {
215
      // Hidden bit is already included in the floating-point format
216
135756
      return format.significandWidth();
217
    }
218
219
220
221
222
    // These should all evaluate to a literal value but are given as
223
    // sbv's to make their use easier and to avoid concerns of overflow.
224
225
184909
    static sbv bias(const fpt &format) {
226
184909
      bwt w(exponentWidth(format));
227
369818
      sbv one(sbv::one(w));
228
229
369818
      return (one << sbv(w,(format.exponentWidth() - 1))) - one;
230
    }
231
232
233
33691
    static sbv maxNormalExponent(const fpt &format) {
234
33691
      return bias(format);
235
    }
236
237
64352
    static sbv minNormalExponent(const fpt &format) {
238
64352
      return -(bias(format) - sbv::one(exponentWidth(format)));
239
    }
240
241
80391
    static sbv maxSubnormalExponent(const fpt &format) {
242
80391
      return -bias(format);
243
    }
244
245
54022
    static sbv minSubnormalExponent(const fpt &format) {
246
54022
      return maxSubnormalExponent(format) - sbv(exponentWidth(format),(significandWidth(format) - 2));
247
    }
248
249
    // Note the different return type as this is used for iteration in remainder
250
119
    static bwt maximumExponentDifference(const fpt &format) {
251
119
      bwt maxNormalExp = (1ULL << (format.exponentWidth() - 1)) - 1;
252
119
      bwt minSubnormalExp = -maxNormalExp - (significandWidth(format) - 2);
253
119
      return maxNormalExp - minSubnormalExp;
254
    }
255
256
    // knownInFormat uses the format invariant to simplify the test
257
6167
    inline prop inNormalRange(const fpt &format, const prop &knownInFormat) const {
258
15578
      return ((minNormalExponent(format) <= exponent) &&
259
15488
	      ((exponent <= maxNormalExponent(format) || knownInFormat)));
260
    }
261
262
    // knownInFormat uses the format invariant to simplify the test
263
26369
    inline prop inSubnormalRange(const fpt &format, const prop &knownInFormat) const {
264
      // To share tests with the inNormalRange test...
265
34071
      prop upperBound(!(minNormalExponent(format) <= exponent));
266
26369
      INVARIANT(upperBound == (exponent <= maxSubnormalExponent(format)));
267
268
37334
      return (((minSubnormalExponent(format) <= exponent) || knownInFormat) &&
269
52738
	      upperBound);
270
    }
271
272
23231
    inline prop inNormalOrSubnormalRange(const fpt &format, const prop &knownInFormat) const {
273
92525
      return ((minSubnormalExponent(format) <= exponent) &&
274
97251
	      (exponent <= maxNormalExponent(format))) || knownInFormat;
275
    }
276
277
278
279
    // The amount needed to normalise the number
280
29363
    inline sbv getSubnormalAmount(const fpt &format) const {
281
      return max<t>(minNormalExponent(format) - exponent,
282
29363
		    sbv::zero(exponent.getWidth()));
283
    }
284
285
323
    inline prop isPositiveInf (void) const {
286
323
      return this->inf && !this->sign;
287
    }
288
289
329
    inline prop isNegativeInf (void) const {
290
329
      return this->inf && this->sign;
291
    }
292
293
294
295
    // Likewise, this is a convenience function
296
26739
    static ubv leadingOne(const bwt sigWidth) {
297
26739
      return ubv::one(sigWidth) << ubv(sigWidth, (sigWidth - 1));
298
    }
299
300
6132
    static ubv nanPattern(const bwt sigWidth) {
301
6132
      return ubv::one(sigWidth) << ubv(sigWidth, (sigWidth - 1)); // For a qNaN, change for sNaN
302
    }
303
304
305
306
125
    unpackedFloat<t> extend (const bwt expExtension, const bwt sigExtension) const {
307
      return unpackedFloat<t>(this->nan,
308
			      this->inf,
309
			      this->zero,
310
			      this->sign,
311
			      this->exponent.extend(expExtension),
312
125
			      this->significand.extend(sigExtension) << ubv((this->significand.getWidth() + sigExtension), sigExtension));
313
    }
314
315
316
    // Moves the leading 1 up to the correct position, adjusting the
317
    // exponent as required.
318
971
    unpackedFloat<t> normaliseUp (const fpt &/*format*/) const {
319
971
      PRECONDITION(!(nan || inf || zero));  // Should not be attempting to normalise these.
320
321
1942
      normaliseShiftResult<t> normal(normaliseShift<t>(this->significand));
322
323
971
      bwt exponentWidth(this->exponent.getWidth());
324
971
      INVARIANT(normal.shiftAmount.getWidth() < exponentWidth); // May loose data / be incorrect for very small exponents and very large significands
325
326
1942
      sbv signedAlignAmount(normal.shiftAmount.resize(exponentWidth).toSigned());
327
1942
      sbv correctedExponent(this->exponent - signedAlignAmount);
328
329
      // Optimisation : could move the zero detect version in if used in all cases
330
      //  catch - it zero detection in unpacking is different.
331
1942
      return unpackedFloat<t>(this->sign, correctedExponent, normal.normalised);
332
    }
333
334
335
195
    unpackedFloat<t> normaliseUpDetectZero (const fpt &format) const {
336
195
      PRECONDITION(!(nan || inf || zero));  // Should not be attempting to normalise these.
337
338
390
      normaliseShiftResult<t> normal(normaliseShift<t>(this->significand));
339
340
195
      bwt exponentWidth(this->exponent.getWidth());
341
195
      INVARIANT(normal.shiftAmount.getWidth() < exponentWidth); // May loose data / be incorrect for very small exponents and very large significands
342
343
390
      sbv signedAlignAmount(normal.shiftAmount.resize(exponentWidth).toSigned());
344
390
      sbv correctedExponent(this->exponent - signedAlignAmount);
345
346
      return ITE(normal.isZero,
347
		 unpackedFloat<t>::makeZero(format, this->sign),
348
390
		 unpackedFloat<t>(this->sign, correctedExponent, normal.normalised));
349
    }
350
351
#if 0
352
    // Moves the leading 1 up to the correct position, adjusting the
353
    // exponent as required.
354
    unpackedFloat<t> normaliseUp (const fpt &/*format*/) const {
355
      PRECONDITION(!(nan || inf || zero));  // Should not be attempting to normalise these.
356
357
      ubv alignAmount(countLeadingZeros<t>(this->significand));
358
359
      ubv alignedSignificand(this->significand.modularLeftShift(alignAmount)); // CLZ means data is not lost
360
361
      sbv signedAlignAmount(alignAmount.extract(this->exponent.getWidth() - 1,0).toSigned());
362
      // May loose data / be incorrect for very small exponents and very large significands
363
      sbv correctedExponent(this->exponent - signedAlignAmount);
364
365
      // Optimisation : could move the zero detect version in if used in all cases
366
      return unpackedFloat<t>(this->sign, correctedExponent, alignedSignificand);
367
    }
368
369
    unpackedFloat<t> normaliseUpDetectZero (const fpt &format) const {
370
      unpackedFloat<t> normal(this->normaliseUp(format));
371
372
      return ITE(this->significand.isAllZeros(),
373
		 unpackedFloat<t>::makeZero(format, this->sign),
374
		 normal);
375
    }
376
#endif
377
378
379
#if 0
380
    unpackedFloat<t> normaliseUp (const fpt &format) const {
381
      PRECONDITION(!(nan || inf || zero));  // Should not be attempting to normalise these.
382
383
      unpackedFloat<t> working(*this);
384
      bwt sigWidth = unpackedFloat<t>::significandWidth(format);
385
      bwt exWidth = unpackedFloat<t>::exponentWidth(format);
386
387
      // TODO : is range checking needed here?  Only in obscure use cases.
388
389
      for (bwt power = previousPowerOfTwo(sigWidth); power != 0; power >>= 1) {
390
	bwt rem = sigWidth - power;
391
392
	INVARIANT(rem > 0);
393
394
	ubv mask(ubv::allOnes(power).extend(rem) << rem);
395
	prop shiftNeeded((mask & working.significand).isAllZeros());
396
397
	// Has to be modular as in the case it is not needed,
398
	// performing the shift will loose information.
399
	working.significand = ITE(shiftNeeded, working.significand.modularLeftShift(power), working.significand);
400
	working.exponent = ITE(shiftNeeded, working.exponent - sbv(exWidth,power), working.exponent);
401
        // Optimisation : rather than add each cycle, build shiftNeeded into a number and add once.
402
      }
403
404
      return working;
405
    }
406
#endif
407
408
409
410
    // Is a well formed unpacked struct of the given format?
411
    // The format is needed to ensure that subnormals are correct.
412
    // This invariant does not hold at all points in the code!
413
23231
    prop valid(const fpt &format) const {
414
415
23231
      bwt exWidth = exponentWidth(format);
416
23231
      bwt sigWidth = significandWidth(format);
417
418
23231
      PRECONDITION((exWidth == exponent.getWidth()) &&
419
		   (sigWidth == significand.getWidth()));
420
421
      // At most one flag is true
422
27957
      prop atMostOneFlag(!(nan && inf) && !(nan && zero) && !(inf && zero));
423
424
      // If one flag is true then exponent and significand are defaults
425
27957
      prop oneFlag(nan || inf || zero);
426
27957
      prop exponentIsDefault(defaultExponent(format) == exponent);
427
27957
      prop significandIsDefault(defaultSignificand(format) == significand);
428
27957
      prop flagImpliesDefaultExponent(IMPLIES(oneFlag, exponentIsDefault));
429
27957
      prop flagImpliesDefaultSignificand(IMPLIES(oneFlag, significandIsDefault));
430
431
      // NaN has sign = 0
432
27957
      prop NaNImpliesSignFalse(IMPLIES(nan, !sign));
433
434
      // Exponent is in range
435
27957
      prop exponentInRange(inNormalOrSubnormalRange(format, prop(false)));
436
437
      // Has a leading one
438
27957
      prop hasLeadingOne(!(leadingOne(unpackedFloat<t>::significandWidth(format)) & significand).isAllZeros());
439
440
      // Subnormal numbers require an additional check to make sure they
441
      // do not have an unrepresentable amount of significand bits.
442
46462
      sbv subnormalAmount(this->getSubnormalAmount(format));
443
23231
      INVARIANT((sbv::zero(exWidth) <= subnormalAmount) &&
444
		(subnormalAmount <= sbv(exWidth,sigWidth)));
445
446
      // Invariant implies this following steps do not loose data
447
46462
      ubv mask(orderEncode<t>((sigWidth >= exWidth) ?
448
			      subnormalAmount.toUnsigned().matchWidth(significand) :
449
			      subnormalAmount.toUnsigned().extract(sigWidth - 1, 0)
450
			      ));
451
452
27957
      prop correctlyAbbreviated((mask & significand).isAllZeros());
453
454
27957
      prop subnormalImpliesTrailingZeros(IMPLIES(inSubnormalRange(format, prop(false)), correctlyAbbreviated));
455
456
457
18505
      return (atMostOneFlag &&
458
18505
	      (flagImpliesDefaultExponent && flagImpliesDefaultSignificand) &&
459
18505
	      NaNImpliesSignFalse &&
460
18505
	      exponentInRange &&
461
37010
	      hasLeadingOne &&
462
46462
	      subnormalImpliesTrailingZeros);
463
    }
464
465
466
467
      /* Older version
468
       * Correct but replaced with a version which gives more propagation friendly assertions.
469
       */
470
#if 0
471
    prop valid(const fpt &format) const {
472
473
      bwt exWidth = exponentWidth(format);
474
      bwt sigWidth = significandWidth(format);
475
476
      PRECONDITION((exWidth == exponent.getWidth()) &&
477
		   (sigWidth == significand.getWidth()));
478
479
      prop hasLeadingOne(!(leadingOne(unpackedFloat<t>::significandWidth(format)) & significand).isAllZeros());
480
481
482
483
      // Subnormal numbers require an additional check to make sure they
484
      // do not have an unrepresentable amount of significand bits.
485
      sbv subnormalAmount(this->getSubnormalAmount(format));
486
      INVARIANT((sbv::zero(exWidth) <= subnormalAmount) &&
487
		(subnormalAmount <= sbv(exWidth,sigWidth)));
488
489
      // Invariant implies this following steps do not loose data
490
      ubv trimmedSubnormalAmount(subnormalAmount.toUnsigned().extract(positionOfLeadingOne(sigWidth),0));
491
      ubv mask(trimmedSubnormalAmount.orderEncode(sigWidth));
492
493
      prop correctlyAbbreviated((mask & significand).isAllZeros());
494
495
496
497
      prop normalCase   (!nan && !inf && !zero && inNormalRange(format, prop(false))    && hasLeadingOne);
498
      prop subnormalCase(!nan && !inf && !zero && inSubnormalRange(format, prop(false)) && hasLeadingOne && correctlyAbbreviated);
499
500
501
502
      prop exponentIsDefault(defaultExponent(format) == exponent);
503
      prop significandIsDefault(defaultSignificand(format) == significand);
504
505
      prop NaNCase ( nan && !inf && !zero && exponentIsDefault && significandIsDefault && !sign);
506
      prop InfCase (!nan &&  inf && !zero && exponentIsDefault && significandIsDefault);
507
      prop ZeroCase(!nan && !inf &&  zero && exponentIsDefault && significandIsDefault);
508
509
      return (NaNCase || InfCase || ZeroCase || normalCase || subnormalCase);
510
511
    }
512
#endif
513
514
515
    // Just for debugging
516
    void print (void) const {
517
      std::cerr << "nan : " << this->nan << '\t'
518
		<< "inf : " << this->inf << '\t'
519
		<< "zero : " << this->zero << '\t'
520
		<< "sign : " << this->sign << '\t'
521
		<< "exponent : " << this->exponent << '\t'
522
		<< "significand : " << this->significand << std::endl;
523
    }
524
525
  };
526
527
template <class t>
528
  struct ite<typename t::prop, unpackedFloat<t> > {
529
14159
  static const unpackedFloat<t> iteOp (const typename t::prop &cond,
530
			    const unpackedFloat<t> &l,
531
			    const unpackedFloat<t> &r) {
532
26748
    return unpackedFloat<t>(ITE(cond, l.nan, r.nan),
533
26748
			    ITE(cond, l.inf, r.inf),
534
26748
			    ITE(cond, l.zero, r.zero),
535
26748
			    ITE(cond, l.sign, r.sign),
536
			    ITE(cond, l.exponent, r.exponent),
537
40907
			    ITE(cond, l.significand, r.significand));
538
    }
539
 };
540
541
542
543
544
}
545
546
#endif