Remove Assembly.
[SquirrelJME.git] / modules / cldc-compact / src / main / java / cc / squirreljme / jvm / SoftFloat.java
blob30aa6a4858281deacc3275c1776baa1b6b5d0b93
1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
3 // SquirrelJME
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc.squirreljme.jvm;
12 import cc.squirreljme.jvm.mle.MathShelf;
13 import cc.squirreljme.runtime.cldc.annotation.SquirrelJMEVendorApi;
14 import cc.squirreljme.runtime.cldc.debug.Debugging;
15 import cc.squirreljme.runtime.cldc.util.UnsignedInteger;
17 /**
18 * Software math operations on 32-bit floats.
20 * This source file uses parts of the Berkeley SoftFloat Release 3e library,
21 * converted into Java. See the 3rd party licenses documentation.
23 * @since 2019/05/24
25 @SquirrelJMEVendorApi
26 @SuppressWarnings({"CommentedOutCode", "MagicNumber", "OverlyComplexClass"})
27 public final class SoftFloat
29 /** The sign mask. */
30 @SquirrelJMEVendorApi
31 public static final int SIGN_MASK =
32 0b1000_0000_0000_0000__0000_0000_0000_0000;
34 /** The zero check mask. */
35 @SquirrelJMEVendorApi
36 public static final int ZERO_CHECK_MASK =
37 0x7FFFFFFF;
39 /** Exponent Mask. */
40 @SquirrelJMEVendorApi
41 public static final int EXPONENT_MASK =
42 0b0111_1111_1000_0000__0000_0000_0000_0000;
44 /** Fraction Mask. */
45 @SquirrelJMEVendorApi
46 public static final int FRACTION_MASK =
47 0b0000_0000_0111_1111__1111_1111_1111_1111;
49 /** The mask for NaN values. */
50 @SquirrelJMEVendorApi
51 public static final int NAN_MASK =
52 0b0111_1111_1000_0000__0000_0000_0000_0000;
54 /** Exponent shift. */
55 private static final byte _EXP_SHIFT =
56 23;
58 /** Default NaN value. */
59 public static final float FLOAT_DEFAULT_NAN =
60 Float.intBitsToFloat(0xFFC0_0000);
62 /** Integer from negative overflow. */
63 private static final int _INT_FROM_NEGOVER =
64 -0x7FFFFFFF - 1;
66 /** Integer from positive overflow. */
67 private static final int _INT_FROM_POSOVER =
68 -0x7FFFFFFF - 1;
70 /** Round near even mode. */
71 private static final int _ROUND_NEAR_EVEN =
74 /**
75 * Not used.
77 * @since 2019/05/24
79 private SoftFloat()
83 /**
84 * Adds two values.
86 * @param __a A.
87 * @param __b B.
88 * @return The result.
89 * @since 2019/05/24
91 @SquirrelJMEVendorApi
92 public static float add(int __a, int __b)
94 throw Debugging.todo();
97 /**
98 * Compares two values, NaN returns {@code -1}.
100 * @param __a A.
101 * @param __b B.
102 * @return The result.
103 * @since 2019/05/24
105 @SquirrelJMEVendorApi
106 @SuppressWarnings("SpellCheckingInspection")
107 public static int cmpl(int __a, int __b)
109 if (SoftFloat.isNaN(__a) || SoftFloat.isNaN(__b))
110 return -1;
112 return SoftFloat.__cmp(__a, __b);
116 * Compares two values, NaN returns {@code 1}.
118 * @param __a A.
119 * @param __b B.
120 * @return The result.
121 * @since 2019/05/24
123 @SquirrelJMEVendorApi
124 @SuppressWarnings("SpellCheckingInspection")
125 public static int cmpg(int __a, int __b)
127 if (SoftFloat.isNaN(__a) || SoftFloat.isNaN(__b))
128 return 1;
130 return SoftFloat.__cmp(__a, __b);
134 * Divides two values.
136 * @param __a A.
137 * @param __b B.
138 * @return The result.
139 * @since 2019/05/24
141 @SquirrelJMEVendorApi
142 public static float div(int __a, int __b)
144 throw Debugging.todo();
148 * Is this Not a Number?
150 * @param __a The value to check.
151 * @return If this is not a number.
152 * @since 2021/04/07
154 @SquirrelJMEVendorApi
155 public static boolean isNaN(int __a)
157 return SoftFloat.NAN_MASK == (__a & SoftFloat.NAN_MASK);
161 * Multiplies two values.
163 * @param __a A.
164 * @param __b B.
165 * @return The result.
166 * @since 2019/05/24
168 @SquirrelJMEVendorApi
169 public static float mul(int __a, int __b)
171 // First value
172 boolean signA = SoftFloat.__signF32UI(__a);
173 int expA = SoftFloat.__expF32UI(__a);
174 int sigA = SoftFloat.__fracF32UI(__a);
176 // Second value
177 boolean signB = SoftFloat.__signF32UI(__b);
178 int expB = SoftFloat.__expF32UI(__b);
179 int sigB = SoftFloat.__fracF32UI(__b);
181 // Will this result in a negative value?
182 boolean signZ = signA ^ signB;
184 boolean returnInfinite = false;
185 int magBits = 0;
186 if (expA == 0xFF)
188 // if ( sigA || ((expB == 0xFF) && sigB) )
189 if (sigA != 0 || ((expB == 0xFF) && (sigB != 0)))
190 return Float.intBitsToFloat(
191 SoftFloat.__propagateNaNF32UI(__a, __b));
193 magBits = expB | sigB;
194 returnInfinite = true;
197 if (!returnInfinite && expB == 0xFF)
199 // if ( sigB )
200 if (sigB != 0)
201 return Float.intBitsToFloat(
202 SoftFloat.__propagateNaNF32UI(__a, __b));
204 magBits = expA | sigA;
205 returnInfinite = true;
208 // Returning infinite value?
209 if (returnInfinite)
211 // if ( ! magBits )
212 if (magBits == 0)
213 return SoftFloat.FLOAT_DEFAULT_NAN;
214 return Float.intBitsToFloat(
215 SoftFloat.__packToF32UI(signZ, 0xFF, 0));
218 // if ( ! expA )
219 if (expA == 0)
221 // if ( ! sigA )
222 if (sigA == 0)
223 return Float.intBitsToFloat(
224 SoftFloat.__packToF32UI(signZ, 0, 0));
226 long normExpSig = SoftFloat.__normSubnormalF32Sig(sigA);
227 expA = (short)MathShelf.longUnpackHigh(normExpSig);
228 sigA = MathShelf.longUnpackLow(normExpSig);
231 // if ( ! expB )
232 if (expB == 0)
234 // if ( ! sigB )
235 if (sigB == 0)
236 return Float.intBitsToFloat(
237 SoftFloat.__packToF32UI(signZ, 0, 0));
239 long normExpSig = SoftFloat.__normSubnormalF32Sig(sigB);
240 expB = (short)MathShelf.longUnpackHigh(normExpSig);
241 sigB = MathShelf.longUnpackLow(normExpSig);
244 int expZ = (short)(expA + expB - 0x7F);
245 sigA = (sigA | 0x0080_0000) << 7;
246 sigB = (sigB | 0x0080_0000) << 8;
248 // sigZ = softfloat_shortShiftRightJam64(
249 // (uint_fast64_t)sigA * sigB, 32); <-- unsigned multiply
250 int sigZ = (int)SoftFloat.__shortShiftRightJam64(
251 (sigA & 0xFFFF_FFFFL) * (sigB & 0xFFFF_FFFFL), 32);
253 // if ( sigZ < 0x40000000 )
254 if (UnsignedInteger.compareUnsigned(sigZ, 0x4000_0000) < 0)
256 expZ = (short)(expZ - 1);
257 sigZ <<= 1;
260 return Float.intBitsToFloat(
261 SoftFloat.__roundPackToF32(signZ, expZ, sigZ));
265 * Negates a value.
267 * @param __a A.
268 * @return The result.
269 * @since 2019/05/24
271 @SquirrelJMEVendorApi
272 public static float neg(int __a)
274 throw Debugging.todo();
278 * Ors a value, used for constant loading.
280 * @param __a A.
281 * @param __b B.
282 * @return The result.
283 * @since 2019/05/24
285 @SquirrelJMEVendorApi
286 public static float or(int __a, int __b)
288 return MathShelf.rawIntToFloat(__a | __b);
292 * Remainders a value.
294 * @param __a A.
295 * @param __b B.
296 * @return The result.
297 * @since 2019/05/24
299 @SquirrelJMEVendorApi
300 public static float rem(int __a, int __b)
302 throw Debugging.todo();
306 * Subtracts values.
308 * @param __a A.
309 * @param __b B.
310 * @return The result.
311 * @since 2019/05/24
313 @SquirrelJMEVendorApi
314 public static float sub(int __a, int __b)
316 throw Debugging.todo();
320 * Converts to double.
322 * @param __a A.
323 * @return The result.
324 * @since 2019/05/24
326 @SquirrelJMEVendorApi
327 public static double toDouble(int __a)
329 throw Debugging.todo();
333 * Converts to integer.
335 * @param __a A.
336 * @return The result.
337 * @since 2019/05/24
339 @SquirrelJMEVendorApi
340 public static int toInteger(int __a)
342 boolean sign = SoftFloat.__signF32UI(__a);
343 int exp = SoftFloat.__expF32UI(__a);
344 int sig = SoftFloat.__fracF32UI(__a);
346 if (exp != 0)
347 sig |= 0x0080_0000;
349 // sig64 = (uint_fast64_t) sig<<32;
350 long sig64 = MathShelf.longPack(0, sig);
351 int shiftDist = 0xAA - exp;
353 if (UnsignedInteger.compareUnsigned(0, shiftDist) < 0)
354 sig64 = SoftFloat.__shiftRightJam64(sig64, shiftDist);
356 return SoftFloat.__roundToI32(sign, sig64);
360 * Converts to long.
362 * @param __a A.
363 * @return The result.
364 * @since 2019/05/24
366 @SquirrelJMEVendorApi
367 public static long toLong(int __a)
369 throw Debugging.todo();
373 * Compares two values.
375 * @param __a A.
376 * @param __b B.
377 * @return The result.
378 * @since 2021/04/07
380 private static int __cmp(int __a, int __b)
382 // Equality, note second means -0 == 0
383 // return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1);
384 if (__a == __b || ((__a | __b) << 1) == 0)
385 return 0;
387 // Less than
388 // (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
389 // : (uiA != uiB) && (signA ^ (uiA < uiB));
390 boolean signA = (0 != (__a & SoftFloat.SIGN_MASK));
391 boolean signB = (0 != (__b & SoftFloat.SIGN_MASK));
392 if (signA != signB)
394 // signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
395 if (signA && ((__a | __b) << 1) != 0)
396 return -1;
399 // (uiA != uiB) && (signA ^ (uiA < uiB))
400 // ^^^ const ^^
401 else if (signA ^ (UnsignedInteger.compareUnsigned(__a, __b) < 0))
402 return -1;
404 // Anything else assume greater than
405 return 1;
409 * Returns the exponent.
411 * @param __a The float to read from.
412 * @return The exponent.
413 * @since 2021/04/10
415 private static int __expF32UI(int __a)
417 // ((int_fast16_t) ((a)>>23) & 0xFF)
418 return (((__a) >>> SoftFloat._EXP_SHIFT) & 0xFF);
422 * Returns the fraction/significand from the floating point value.
424 * @param __a The float to read from.
425 * @return The fraction/significand.
426 * @since 2021/04/10
428 private static int __fracF32UI(int __a)
430 return (__a & SoftFloat.FRACTION_MASK);
434 * Gets if this is a NaN.
436 * @param __a The value to check.
437 * @return If this is a NaN.
438 * @since 2021/04/10
440 private static boolean __isNaNF32UI(int __a)
442 return ((~(__a) & 0x7F800000) == 0) &&
443 ((__a) & 0x007FFFFF) != 0;
447 * Gets if this is a signaling NaN.
449 * @param __a The value to check.
450 * @return If this is a signaling NaN.
451 * @since 2021/04/10
453 private static boolean __isSigNaNF32UI(int __a)
455 return ((__a & 0x7FC00000) == 0x7F800000) &&
456 (__a & 0x003FFFFF) != 0;
460 * Normalized round packed to 32-bit float.
462 * @param __sign The sign.
463 * @param __exp The exponent.
464 * @param __sig The significand.
465 * @return The resultant value.
466 * @since 2021/04/08
468 protected static int __normRoundPackToF32(boolean __sign, int __exp,
469 int __sig)
471 int shiftDist;
473 // shiftDist = softfloat_countLeadingZeros32( __sig ) - 1;
474 shiftDist = Integer.numberOfLeadingZeros(__sig) - 1;
475 __exp -= shiftDist;
477 // if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) {
478 if (7 <= shiftDist &&
479 UnsignedInteger.compareUnsigned(__exp, 0xFD) < 0)
481 // uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7));
482 return SoftFloat.__packToF32UI(__sign,
483 (__sig != 0 ? __exp : 0),
484 __sig << (shiftDist - 7));
487 // return softfloat_roundPackToF32( sign, exp, sig<<shiftDist );
488 return SoftFloat.__roundPackToF32(__sign, __exp,
489 __sig << shiftDist);
493 * Normalizes a subnormal 32-bit float significand.
495 * @param __sig The significand.
496 * @return The normalized value, the exponent is the high value and
497 * the significand is the low value.
498 * @since 2021/04/10
500 private static long __normSubnormalF32Sig(int __sig)
502 // softfloat_countLeadingZeros32( sig ) - 8;
503 int shiftDist = Integer.numberOfLeadingZeros(__sig) - 8;
505 // struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
506 // exp = 1 - shiftDist ,, sig = sig<<shiftDist
507 return MathShelf.longPack(__sig << shiftDist,
508 (short)(1 - shiftDist));
512 * Packs value to an unsigned integer, note that some of these values are
513 * perfectly fine to overflow into each other such as the significand
514 * being larger than the value.
516 * @param __sign Sign bit.
517 * @param __exp Exponent.
518 * @param __sig Significand.
519 * @return The packed value.
520 * @since 2021/04/08
522 protected static int __packToF32UI(boolean __sign, int __exp, int __sig)
524 // (((uint32_t) (sign)<<31) + ((uint32_t) (exp)<<23) + (sig))
525 return (__sign ? SoftFloat.SIGN_MASK : 0) + ((__exp) << 23) + (__sig);
529 * Propagates the given NaN values.
531 * @param __a The first value.
532 * @param __b The second value.
533 * @return The propagated NaN.
534 * @since 2021/04/10
536 private static int __propagateNaNF32UI(int __a, int __b)
538 boolean isSigNaNA = SoftFloat.__isSigNaNF32UI(__a);
539 boolean isSigNaNB = SoftFloat.__isSigNaNF32UI(__b);
541 // Make NaNs non-signaling.
542 int uiNonSigA = __a | 0x00400000;
543 int uiNonSigB = __b | 0x00400000;
545 // Are either of these signaling?
546 if (isSigNaNA | isSigNaNB)
548 if (isSigNaNA)
550 if (!isSigNaNB)
551 return SoftFloat.__isNaNF32UI(__b) ? uiNonSigB : uiNonSigA;
553 else
554 return SoftFloat.__isNaNF32UI(__a) ? uiNonSigA : uiNonSigB;
557 int uiMagA = __a & 0x7FFFFFFF;
558 int uiMagB = __b & 0x7FFFFFFF;
560 if (UnsignedInteger.compareUnsigned(uiMagA, uiMagB) < 0)
561 return uiNonSigB;
563 if (UnsignedInteger.compareUnsigned(uiMagB, uiMagA) < 0)
564 return uiNonSigA;
566 // return (uiNonSigA < uiNonSigB) ? uiNonSigA : uiNonSigB;
567 if (UnsignedInteger.compareUnsigned(uiNonSigA, uiNonSigB) < 0)
568 return uiNonSigA;
569 return uiNonSigB;
573 * Round and pack to float.
575 * @param __sign The sign.
576 * @param __exp The exponent.
577 * @param __sig The significand.
578 * @return The resultant value.
579 * @since 2021/04/08
581 private static int __roundPackToF32(boolean __sign, int __exp, int __sig)
583 int roundIncrement = 0x40;
584 int roundBits = __sig & 0x7F;
586 // if ( 0xFD <= (unsigned int) exp )
587 if (UnsignedInteger.compareUnsigned(0xFD, __exp) <= 0)
589 // Negative exponent?
590 if (__exp < 0)
592 __sig = SoftFloat.__shiftRightJam32(__sig, -__exp);
593 __exp = 0;
594 roundBits = __sig & 0x7F;
597 // else if ((0xFD < exp) || (0x80000000 <= sig + roundIncrement))
598 else if (0xFD < __exp ||
599 UnsignedInteger.compareUnsigned(0x8000_0000,
600 __sig + roundIncrement) <= 0)
602 // uiZ = packToF32UI(__sign, 0xFF, 0) - !roundIncrement;
603 return SoftFloat.__packToF32UI(__sign, 0xFF, 0);
607 // sig = (sig + roundIncrement)>>7;
608 __sig = (__sig + roundIncrement) >>> 7;
610 // sig &= ~(uint_fast32_t) (! (roundBits ^ 0x40) & roundNearEven);
611 __sig &= ~(((roundBits ^ 0x40) == 0 ? 1 : 0) & 1);
613 // if ( ! sig ) exp = 0;
614 if (__sig == 0)
615 __exp = 0;
617 // uiZ = packToF32UI( sign, exp, sig );
618 return SoftFloat.__packToF32UI(__sign, __exp, __sig);
622 * Rounds to 32-bit integer.
624 * @param __sign The sign.
625 * @param __sig The significand.
626 * @return The resultant integer.
627 * @since 2021/04/10
629 private static int __roundToI32(boolean __sign, long __sig)
631 int roundBits = ((int)__sig) & 0xFFF;
632 int roundIncrement = 0x800;
633 __sig += roundIncrement;
635 // if ( sig & UINT64_C( 0xFFFFF00000000000 ) ) goto invalid;
636 if ((__sig & 0xFFFF_F000_0000_0000L) != 0)
637 return __sign ? SoftFloat._INT_FROM_NEGOVER :
638 SoftFloat._INT_FROM_POSOVER;
640 // sig32 = sig>>12;
641 int sig32 = (int)(__sig >>> 12);
643 // if (roundBits == 0x800) && (roundMode == softfloat_round_near_even)
644 if (roundBits == 0x800)
645 sig32 &= ~1;
647 int z = __sign ? -sig32 : sig32;
649 // if ( z && ((z < 0) ^ sign) ) goto invalid;
650 if (z != 0 && ((z < 0) ^ __sign))
651 return __sign ? SoftFloat._INT_FROM_NEGOVER :
652 SoftFloat._INT_FROM_POSOVER;
654 return z;
658 * Shift right and jam float.
660 * @param __v The value.
661 * @param __uDist The distance.
662 * @return The jammed value.
663 * @since 2021/04/08
665 private static int __shiftRightJam32(int __v, int __uDist)
667 // uint_fast16_t dist
668 // (dist < 31) ? a>>dist | ((uint32_t) (a<<(-dist & 31)) != 0)
669 if (UnsignedInteger.compareUnsigned(__uDist, 31) < 0)
670 return __v >> __uDist | (((__v << (-__uDist & 31)) != 0) ? 1 : 0);
672 // (a != 0)
673 return (__v != 0 ? 1 : 0);
677 * Shift right and jam 64-bit.
679 * @param __a The value.
680 * @param __dist The distance.
681 * @return The result.
682 * @since 2021/04/10
684 private static long __shiftRightJam64(long __a, int __dist)
686 // (__dist < 63) ? __a>>__dist |
687 // ((uint64_t) (__a<<(-__dist & 63)) != 0) : (__a != 0);
688 if (UnsignedInteger.compareUnsigned(__dist, 63) < 0)
689 return __a >>> __dist |
690 (((__a << (-__dist & 63)) != 0) ? 1 : 0);
691 return (__a != 0 ? 1 : 0);
695 * Short shift right jam at 64-bits.
697 * @param __a The value to jam.
698 * @param __dist The distance.
699 * @return The jammed value.
700 * @since 2021/04/10
702 private static long __shortShiftRightJam64(long __a, int __dist)
704 // return a>>dist | ((a & (((uint_fast64_t) 1<<dist) - 1)) != 0);
705 return __a >>> __dist |
706 (((__a & ((1L << __dist) - 1)) != 0) ? 1 : 0);
710 * Returns whether the sign bit is set.
712 * @param __a The float to read from.
713 * @return If the sign bit is set.
714 * @since 2021/04/10
716 private static boolean __signF32UI(int __a)
718 return (__a & SoftFloat.SIGN_MASK) != 0;