GCC Code Coverage Report
Directory: . Exec Total Coverage
File: deps/install/include/symfpu/core/convert.h Lines: 46 125 36.8 %
Date: 2021-03-23 Branches: 74 370 20.0 %

Line Exec Source
1
/*
2
** Copyright (C) 2018 Martin Brain
3
**
4
** See the file LICENSE for licensing information.
5
*/
6
7
/*
8
** convert.h
9
**
10
** Martin Brain
11
** martin.brain@cs.ox.ac.uk
12
** 03/02/14
13
**
14
** Conversion from unpacked floats in one format to another.
15
**
16
*/
17
18
#include "symfpu/core/unpackedFloat.h"
19
#include "symfpu/core/rounder.h"
20
21
#ifndef SYMFPU_CONVERT
22
#define SYMFPU_CONVERT
23
24
namespace symfpu {
25
26
template <class t>
27
23
unpackedFloat<t> convertFloatToFloat (const typename t::fpt &sourceFormat,
28
				      const typename t::fpt &targetFormat,
29
				      const typename t::rm &roundingMode,
30
				      const unpackedFloat<t> &input) {
31
32
23
  PRECONDITION(input.valid(sourceFormat));
33
34
  typedef typename t::bwt bwt;
35
  //typedef typename t::prop prop;
36
  //typedef typename t::ubv ubv;
37
  //typedef typename t::sbv sbv;
38
39
  // increased includes equality
40
23
  bool exponentIncreased = unpackedFloat<t>::exponentWidth(sourceFormat) <= unpackedFloat<t>::exponentWidth(targetFormat);
41
23
  bool significandIncreased = unpackedFloat<t>::significandWidth(sourceFormat) <= unpackedFloat<t>::significandWidth(targetFormat);
42
43
23
  bwt expExtension = (exponentIncreased) ? unpackedFloat<t>::exponentWidth(targetFormat) - unpackedFloat<t>::exponentWidth(sourceFormat) : 0;
44
23
  bwt sigExtension = (significandIncreased) ? unpackedFloat<t>::significandWidth(targetFormat) - unpackedFloat<t>::significandWidth(sourceFormat) : 0;
45
46
46
  unpackedFloat<t> extended(input.extend(expExtension, sigExtension));
47
48
  // Format sizes are literal so it is safe to branch on them
49
23
  if (exponentIncreased && significandIncreased) {
50
    // Fast path strict promotions
51
52
7
    POSTCONDITION(extended.valid(targetFormat));
53
54
7
    return extended;
55
56
  } else {
57
58
32
    unpackedFloat<t> rounded(rounder(targetFormat, roundingMode, extended));
59
60
64
    unpackedFloat<t> result(ITE(input.getNaN(),
61
				unpackedFloat<t>::makeNaN(targetFormat),
62
16
				ITE(input.getInf(),
63
				    unpackedFloat<t>::makeInf(targetFormat, input.getSign()),
64
16
				    ITE(input.getZero(),
65
					unpackedFloat<t>::makeZero(targetFormat, input.getSign()),
66
					rounded))));
67
68
16
    POSTCONDITION(result.valid(targetFormat));
69
70
16
    return result;
71
  }
72
}
73
74
75
template <class t>
76
160
unpackedFloat<t> roundToIntegral (const typename t::fpt &format,
77
				  const typename t::rm &roundingMode,
78
				  const unpackedFloat<t> &input) {
79
80
160
  PRECONDITION(input.valid(format));
81
82
  typedef typename t::bwt bwt;
83
  typedef typename t::prop prop;
84
  typedef typename t::ubv ubv;
85
  typedef typename t::sbv sbv;
86
87
320
  sbv exponent(input.getExponent());
88
160
  bwt exponentWidth(exponent.getWidth());
89
90
320
  sbv packedSigWidth(exponentWidth, format.packedSignificandWidth());
91
320
  sbv unpackedSigWidth(exponentWidth, format.significandWidth());
92
93
  // Fast path for things that must be integral
94
180
  prop isIntegral(exponent >= packedSigWidth);
95
180
  prop isSpecial(input.getNaN() || input.getInf() || input.getZero());
96
180
  prop isID(isIntegral || isSpecial);
97
160
  probabilityAnnotation<t>(isID, LIKELY);
98
  // TODO : fast path the cases that don't round up
99
100
101
  // Otherwise, compute rounding location
102
320
  sbv initialRoundingPoint(expandingSubtract<t>(packedSigWidth,exponent));  // Expansion only needed in obscure formats
103
640
  sbv roundingPoint(collar<t>(initialRoundingPoint,
104
320
			      sbv::zero(exponentWidth + 1),
105
			      unpackedSigWidth.extend(1).increment()));
106
107
  // Round
108
320
  ubv significand(input.getSignificand());
109
320
  significandRounderResult<t> roundedResult(variablePositionRound<t>(roundingMode, input.getSign(), significand,
110
								     roundingPoint.toUnsigned().matchWidth(significand),
111
								     prop(false), // TODO : Could actually be exponent >= 0
112
								     isID));      // The fast-path case so just deactives some code
113
114
  // Reconstruct
115
  // Note this is not in a valid form if significand is all zeros
116
  // The max is necessary to catch cases when we round up to one from very small numbers
117
  // The rounder ensures these are zero if they don't round up
118
320
  unpackedFloat<t> reconstructed(input.getSign(),
119
				 max<t>(conditionalIncrement<t>(roundedResult.incrementExponent, exponent),
120
					sbv::zero(exponentWidth)),
121
				 roundedResult.significand);
122
123
124
440
  unpackedFloat<t> result(ITE(isID,
125
			      input,
126
280
			      ITE(roundedResult.significand.isAllZeros(),
127
				  unpackedFloat<t>::makeZero(format, input.getSign()),
128
				  reconstructed)));
129
130
160
  POSTCONDITION(result.valid(format));
131
132
320
  return result;
133
134
135
  #if 0
136
  // increased includes equality
137
  bool exponentIncreased = unpackedFloat<t>::exponentWidth(sourceFormat) <= unpackedFloat<t>::exponentWidth(targetFormat);
138
  bool significandIncreased = unpackedFloat<t>::significandWidth(sourceFormat) <= unpackedFloat<t>::significandWidth(targetFormat);
139
140
  bwt expExtension = (exponentIncreased) ? unpackedFloat<t>::exponentWidth(targetFormat) - unpackedFloat<t>::exponentWidth(sourceFormat) : 0;
141
  bwt sigExtension = (significandIncreased) ? unpackedFloat<t>::significandWidth(targetFormat) - unpackedFloat<t>::significandWidth(sourceFormat) : 0;
142
143
  unpackedFloat<t> extended(input.extend(expExtension, sigExtension));
144
145
  // Format sizes are literal so it is safe to branch on them
146
  if (exponentIncreased && significandIncreased) {
147
    // Fast path strict promotions
148
149
    POSTCONDITION(extended.valid(targetFormat));
150
151
    return extended;
152
153
  } else {
154
155
    unpackedFloat<t> rounded(rounder(targetFormat, roundingMode, extended));
156
157
    unpackedFloat<t> result(ITE(input.getNaN(),
158
				unpackedFloat<t>::makeNaN(targetFormat),
159
				ITE(input.getInf(),
160
				    unpackedFloat<t>::makeInf(targetFormat, input.getSign()),
161
				    ITE(input.getZero(),
162
					unpackedFloat<t>::makeZero(targetFormat, input.getSign()),
163
					rounded))));
164
165
    POSTCONDITION(result.valid(targetFormat));
166
167
    return result;
168
  }
169
  #endif
170
171
}
172
173
174
template <class t>
175
  unpackedFloat<t> convertUBVToFloat (const typename t::fpt &targetFormat,
176
				      const typename t::rm &roundingMode,
177
				      const typename t::ubv &input,
178
				      const typename t::bwt &decimalPointPosition = 0) {
179
180
  typedef typename t::bwt bwt;
181
  typedef typename t::prop prop;
182
  typedef typename t::sbv sbv;
183
  typedef typename t::fpt fpt;
184
185
  bwt inputWidth(input.getWidth());
186
187
  PRECONDITION(decimalPointPosition <= inputWidth);
188
189
  // Devise an appropriate format
190
  bwt initialExponentWidth(bitsToRepresent<bwt>(inputWidth) + 1); // +1 as unsigned -> signed
191
  fpt initialFormat(initialExponentWidth, inputWidth);
192
  bwt actualExponentWidth(unpackedFloat<t>::exponentWidth(initialFormat));
193
194
  // Build
195
  unpackedFloat<t> initial(prop(false), sbv(actualExponentWidth, (inputWidth - 1) - decimalPointPosition), input);  // inputWidth - 1 as we want one bit above the decimal point
196
197
  // Normalise
198
  unpackedFloat<t> normalised(initial.normaliseUpDetectZero(initialFormat));
199
200
  // Round (the conversion will catch the cases where no rounding is needed)
201
  return convertFloatToFloat(initialFormat, targetFormat, roundingMode, normalised);
202
 }
203
204
205
template <class t>
206
4
  unpackedFloat<t> convertSBVToFloat (const typename t::fpt &targetFormat,
207
				      const typename t::rm &roundingMode,
208
				      const typename t::sbv &input,
209
				      const typename t::bwt &decimalPointPosition = 0) {
210
  typedef typename t::bwt bwt;
211
  typedef typename t::prop prop;
212
  typedef typename t::sbv sbv;
213
  typedef typename t::fpt fpt;
214
215
4
  bwt inputWidth(input.getWidth());
216
217
4
  PRECONDITION(decimalPointPosition <= inputWidth);
218
219
  // Devise an appropriate format
220
4
  bwt initialExponentWidth(bitsToRepresent<bwt>(inputWidth) + 1); // +1 as unsigned -> signed
221
4
  fpt initialFormat(initialExponentWidth, inputWidth + 1);        // +1 as signed -> unsigned
222
4
  bwt actualExponentWidth(unpackedFloat<t>::exponentWidth(initialFormat));
223
224
  // Work out the sign
225
4
  prop negative(input < sbv::zero(inputWidth));
226
227
  // Build
228
8
  unpackedFloat<t> initial(negative, sbv(actualExponentWidth, inputWidth - decimalPointPosition), (abs<t,sbv>(input.extend(1))).toUnsigned());
229
230
  // Normalise
231
8
  unpackedFloat<t> normalised(initial.normaliseUpDetectZero(initialFormat));
232
233
  // Round (the conversion will catch the cases where no rounding is needed)
234
8
  return convertFloatToFloat(initialFormat, targetFormat, roundingMode, normalised);
235
 }
236
237
238
 // Common conversion code for both convert to sgined and to unsigned.
239
 // Note that the results will be junk if it is not in bounds, etc.
240
 // convertFloatToUBV and convertFloatToSBV handle all of that logic.
241
 template <class t>
242
   significandRounderResult<t> convertFloatToBV (const typename t::fpt &format,
243
						 const typename t::rm &roundingMode,
244
						 const unpackedFloat<t> &input,
245
						 const typename t::bwt &targetWidth,
246
						 const typename t::bwt &decimalPointPosition) {
247
248
   typedef typename t::bwt bwt;
249
   typedef typename t::prop prop;
250
   typedef typename t::ubv ubv;
251
   typedef typename t::sbv sbv;
252
253
254
   PRECONDITION(decimalPointPosition < targetWidth);
255
256
257
   // TODO : fast path the RTZ / don't need to round case
258
259
   bwt maxShift(targetWidth + 1); // + 1 as we have to shift over the guard bit
260
   bwt maxShiftBits(bitsToRepresent(maxShift) + 1); // +1 as we want it to be signed
261
262
   bwt exponentWidth(input.getExponent().getWidth());
263
   bwt workingExponentWidth((exponentWidth >= maxShiftBits) ?
264
			    exponentWidth : maxShiftBits);
265
266
   sbv maxShiftAmount(workingExponentWidth, maxShift);
267
   sbv exponent(input.getExponent().matchWidth(maxShiftAmount));
268
269
270
   // Optimisation : compact the significand in the case targetWidth < significantWidth
271
   ubv inputSignificand(input.getSignificand());
272
   bwt inputSignificandWidth(inputSignificand.getWidth());
273
   ubv *working = NULL;
274
   if (targetWidth + 2 < inputSignificandWidth) {
275
276
     ubv dataAndGuard(inputSignificand.extract(inputSignificandWidth - 1, (inputSignificandWidth - targetWidth) - 1));
277
     prop sticky(!inputSignificand.extract((inputSignificandWidth - targetWidth) - 2, 0).isAllZeros());
278
279
     working = new ubv(dataAndGuard.append(ubv(sticky)));
280
   } else {
281
     working = new ubv(inputSignificand);
282
   }
283
   ubv significand(*working);
284
   delete working;
285
   bwt significandWidth(significand.getWidth());
286
287
   // Handle zero
288
   ubv zerodSignificand(significand &
289
			ITE(input.getZero(), ubv::zero(significandWidth), ubv::allOnes(significandWidth)));
290
   ubv expandedSignificand(zerodSignificand.extend(maxShift)); // Start with the significand in the sticky position.
291
                                                               // targetWidth +1 is for the guard bit
292
293
   // Align
294
   sbv shiftAmount(collar<t>(expandingAdd<t>(exponent,
295
					     sbv(workingExponentWidth, decimalPointPosition + 2)),  // +1 to guard, +1 to LSB
296
			     sbv::zero(workingExponentWidth + 1),
297
			     maxShiftAmount.extend(1)));
298
   ubv convertedShiftAmount(shiftAmount.resize(bitsToRepresent(maxShift) + 1 /* +1 for sign bit, safe due to collar */
299
					       ).toUnsigned().matchWidth(expandedSignificand));
300
   ubv aligned(expandedSignificand << convertedShiftAmount); // Safe by collar
301
302
303
   // Fixed position round
304
   significandRounderResult<t> rounded(fixedPositionRound<t>(roundingMode, input.getSign(),
305
							     aligned, targetWidth,
306
							     prop(false), prop(false)));
307
308
   return rounded;
309
 }
310
311
 // A more compact version for round to zero
312
 // Only handles normal, subnormal and zero cases, overflow of targetWidth will give junk.
313
 // Inf, NaN, and overflow must be handled by the caller.
314
 template <class t>
315
   significandRounderResult<t> convertFloatToBVRTZ (const typename t::fpt &format,
316
						    const unpackedFloat<t> &input,
317
						    const typename t::bwt &targetWidth,
318
						    const typename t::bwt &decimalPointPosition) {
319
   typedef typename t::bwt bwt;
320
   typedef typename t::prop prop;
321
   typedef typename t::ubv ubv;
322
   typedef typename t::sbv sbv;
323
324
   PRECONDITION(targetWidth > 0);
325
   PRECONDITION(decimalPointPosition < targetWidth);
326
327
   // A working significand of the right length
328
   ubv significand(input.getSignificand());
329
   bwt significandWidth(significand.getWidth());
330
331
   ubv significantSignificand(significand.extract(significandWidth - 1,
332
						  ((targetWidth < significandWidth) ? significandWidth - targetWidth : 0)));
333
   bwt ssWidth(significantSignificand.getWidth());
334
335
336
   // Handle zero and fractional cases
337
   sbv exponent(input.getExponent());
338
   bwt exponentWidth(exponent.getWidth());
339
340
   prop fraction(input.getExponent() < sbv::zero(exponentWidth));
341
   ubv zerodSignificand(significantSignificand &
342
			ITE(input.getZero() || fraction, ubv::zero(ssWidth), ubv::allOnes(ssWidth)));
343
344
   ubv expandedSignificand(zerodSignificand.extend(targetWidth - 1)); // Start with the significand in the LSB of output
345
346
347
   // Prepare exponent
348
   bwt maxShift(targetWidth - 1); // - 1 as we are already at LSB
349
   bwt maxShiftBits(bitsToRepresent(maxShift)); // Don't care about it being signed
350
351
   ubv convertedExponent(exponent.toUnsigned());
352
   bwt topExtractedBit(((maxShiftBits >  (exponentWidth - 1)) ? exponentWidth : maxShiftBits) - 1);
353
354
   ubv shiftBits(convertedExponent.extract(topExtractedBit, 0));
355
   ubv shiftOperand(shiftBits.matchWidth(expandedSignificand));
356
357
   // Align
358
   ubv shifted(expandedSignificand.modularLeftShift(shiftOperand));
359
   bwt shiftedWidth(shifted.getWidth());
360
361
   // Extract
362
   ubv result(shifted.extract(shiftedWidth - 1, shiftedWidth - targetWidth));
363
364
   return significandRounderResult<t>(result, prop(false));
365
 }
366
367
368
369
 // Decimal point position in the bit in the output on the left hand side of the decimal point
370
 // I.E. if it is positive then it is converting to a fix-point number
371
 template <class t>
372
   typename t::ubv convertFloatToUBV (const typename t::fpt &format,
373
				      const typename t::rm &roundingMode,
374
				      const unpackedFloat<t> &input,
375
				      const typename t::bwt &targetWidth,
376
				      const typename t::ubv &undefValue,
377
				      const typename t::bwt &decimalPointPosition = 0) {
378
379
   typedef typename t::bwt bwt;
380
   typedef typename t::prop prop;
381
   typedef typename t::ubv ubv;
382
   typedef typename t::sbv sbv;
383
384
385
   PRECONDITION(decimalPointPosition < targetWidth);
386
387
388
   // Invalid cases
389
   prop specialValue(input.getInf() || input.getNaN());
390
391
   bwt maxExponentValue(targetWidth);
392
   bwt maxExponentBits(bitsToRepresent(maxExponentValue) + 1);
393
394
   bwt exponentWidth(input.getExponent().getWidth());
395
   bwt workingExponentWidth((exponentWidth >= maxExponentBits) ?
396
			    exponentWidth : maxExponentBits);
397
398
   sbv maxExponent(workingExponentWidth, maxExponentValue);
399
   sbv exponent(input.getExponent().matchWidth(maxExponent));
400
401
   prop tooLarge(exponent >= maxExponent);
402
403
   prop tooNegative(input.getSign() &&
404
		    !input.getZero() &&  // Zero is handled elsewhere
405
		    sbv::zero(workingExponentWidth) <= exponent);  // Can't round to 0
406
407
   prop earlyUndefinedResult(specialValue || tooLarge || tooNegative);
408
   probabilityAnnotation<t>(earlyUndefinedResult, LIKELY); // Convertable values are rare
409
410
411
   // Fixed position round
412
   significandRounderResult<t> rounded(convertFloatToBV(format, roundingMode, input,
413
							targetWidth, decimalPointPosition));
414
415
   // TODO : fast path negative by converting exp==0 into guard and exp < 0 into sticky
416
417
   // Put the result together
418
   prop undefinedResult(earlyUndefinedResult ||
419
			rounded.incrementExponent ||    // Overflow
420
			(input.getSign() && !rounded.significand.isAllZeros()));  // Negative case
421
422
   ubv result(ITE(undefinedResult,
423
		  undefValue,
424
		  rounded.significand));
425
426
   return result;
427
 }
428
429
  // Decimal point position in the bit in the output on the left hand side of the decimal point
430
  // I.E. if it is positive then it is converting to a fix-point number
431
  template <class t>
432
    typename t::sbv convertFloatToSBV (const typename t::fpt &format,
433
				       const typename t::rm &roundingMode,
434
				       const unpackedFloat<t> &input,
435
				       const typename t::bwt &targetWidth,
436
				       const typename t::sbv &undefValue,
437
				       const typename t::bwt &decimalPointPosition = 0) {
438
439
   typedef typename t::bwt bwt;
440
   typedef typename t::prop prop;
441
   //typedef typename t::ubv ubv;
442
   typedef typename t::sbv sbv;
443
444
445
   PRECONDITION(decimalPointPosition < targetWidth);
446
447
448
   // Invalid cases
449
   prop specialValue(input.getInf() || input.getNaN());
450
451
   bwt maxExponentValue(targetWidth);
452
   bwt maxExponentBits(bitsToRepresent(maxExponentValue) + 1);
453
454
   bwt exponentWidth(input.getExponent().getWidth());
455
   bwt workingExponentWidth((exponentWidth >= maxExponentBits) ?
456
			    exponentWidth : maxExponentBits);
457
458
   sbv maxExponent(workingExponentWidth, maxExponentValue);
459
   sbv exponent(input.getExponent().matchWidth(maxExponent));
460
461
   prop tooLarge(exponent >= maxExponent);
462
463
   prop earlyUndefinedResult(specialValue || tooLarge);
464
   probabilityAnnotation<t>(earlyUndefinedResult, LIKELY); // Convertable values are rare
465
466
467
   // Fixed position round
468
   // (It is tempting to think that this could be done with targetWidth - 1 bits but that
469
   // missed the case of things like -128.05 -> int8_t)
470
   significandRounderResult<t> rounded(convertFloatToBV(format, roundingMode, input,
471
							targetWidth, decimalPointPosition));
472
473
   // Put the result together
474
   bwt roundSigWidth(rounded.significand.getWidth());
475
   prop undefinedResult(earlyUndefinedResult ||
476
			rounded.incrementExponent ||    // Definite Overflow
477
			(rounded.significand.extract(roundSigWidth - 1,
478
						     roundSigWidth - 1).isAllOnes() &&
479
			 !(input.getSign() && rounded.significand.extract(roundSigWidth - 2, 0).isAllZeros()))); // -2^{n-1} is the only safe "overflow" case
480
481
482
   sbv result(ITE(undefinedResult,
483
		  undefValue,
484
		  conditionalNegate<t,sbv,prop>(input.getSign(), rounded.significand.toSigned())));
485
486
   return result;
487
 }
488
489
}
490
491
#endif