Commit e1f61725 authored by Stephanie Gawroriski's avatar Stephanie Gawroriski
Browse files

Cherry pick soft math from SummerCoat WIP.

parent 66861fb7
......@@ -28,14 +28,14 @@ public class SoftDouble
/**
* Adds two values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static double add(int __ah, int __al, int __bh, int __bl)
public static double add(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -44,14 +44,14 @@ public class SoftDouble
/**
* Compares two values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static int cmpl(int __ah, int __al, int __bh, int __bl)
public static int cmpl(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -60,14 +60,14 @@ public class SoftDouble
/**
* Compares two values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static int cmpg(int __ah, int __al, int __bh, int __bl)
public static int cmpg(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -76,14 +76,14 @@ public class SoftDouble
/**
* Divides two values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static double div(int __ah, int __al, int __bh, int __bl)
public static double div(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -92,14 +92,14 @@ public class SoftDouble
/**
* Multiplies two values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static double mul(int __ah, int __al, int __bh, int __bl)
public static double mul(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -108,12 +108,12 @@ public class SoftDouble
/**
* Negates a value.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public static double neg(int __ah, int __al)
public static double neg(int __al, int __ah)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -122,29 +122,29 @@ public class SoftDouble
/**
* ORs value, used for constants.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/27
*/
public static double or(int __ah, int __al, int __bh, int __bl)
public static double or(int __al, int __ah, int __bl, int __bh)
{
return Assembly.doublePack(__ah | __bh, __al | __bl);
return Assembly.doublePack(__al | __bl, __ah | __bh);
}
/**
* Remainders a value.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static double rem(int __ah, int __al, int __bh, int __bl)
public static double rem(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -153,14 +153,14 @@ public class SoftDouble
/**
* Subtracts values.
*
* @param __ah A high.
* @param __al A low.
* @param __bh B high.
* @param __ah A high.
* @param __bl B low.
* @param __bh B high.
* @return The result.
* @since 2019/05/24
*/
public static double sub(int __ah, int __al, int __bh, int __bl)
public static double sub(int __al, int __ah, int __bl, int __bh)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -169,12 +169,12 @@ public class SoftDouble
/**
* Converts to float.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public static float toFloat(int __ah, int __al)
public static float toFloat(int __al, int __ah)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -183,12 +183,12 @@ public class SoftDouble
/**
* Converts to integer.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public static int toInteger(int __ah, int __al)
public static int toInteger(int __al, int __ah)
{
Assembly.breakpoint();
throw new todo.TODO();
......@@ -197,12 +197,12 @@ public class SoftDouble
/**
* Converts to long.
*
* @param __ah A high.
* @param __al A low.
* @param __ah A high.
* @return The result.
* @since 2019/05/24
*/
public static long toLong(int __ah, int __al)
public static long toLong(int __al, int __ah)
{
Assembly.breakpoint();
throw new todo.TODO();
......
......@@ -9,13 +9,55 @@
package cc.squirreljme.jvm;
import cc.squirreljme.runtime.cldc.util.UnsignedInteger;
/**
* Software math operations on 32-bit floats.
*
* This source file uses parts of the Berkeley SoftFloat Release 3e library,
* converted into Java. See the 3rd party licenses documentation.
*
* @since 2019/05/24
*/
public class SoftFloat
@SuppressWarnings({"CommentedOutCode", "MagicNumber"})
public final class SoftFloat
{
/** The sign mask. */
public static final int SIGN_MASK =
0b1000_0000_0000_0000__0000_0000_0000_0000;
/** Exponent Mask. */
public static final int EXPONENT_MASK =
0b0111_1111_1000_0000__0000_0000_0000_0000;
/** Fraction Mask. */
public static final int FRACTION_MASK =
0b0000_0000_0111_1111__1111_1111_1111_1111;
/** The mask for NaN values. */
public static final int NAN_MASK =
0b0111_1111_1000_0000__0000_0000_0000_0000;
/** Exponent shift. */
private static final byte _EXP_SHIFT =
23;
/** Default NaN value. */
public static final float FLOAT_DEFAULT_NAN =
Float.intBitsToFloat(0xFFC0_0000);
/** Integer from negative overflow. */
private static final int _INT_FROM_NEGOVER =
-0x7FFFFFFF - 1;
/** Integer from positive overflow. */
private static final int _INT_FROM_POSOVER =
-0x7FFFFFFF - 1;
/** Round near even mode. */
private static final int _ROUND_NEAR_EVEN =
0;
/**
* Not used.
*
......@@ -40,31 +82,37 @@ public class SoftFloat
}
/**
* Compares two values.
* Compares two values, NaN returns {@code -1}.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2019/05/24
*/
@SuppressWarnings("SpellCheckingInspection")
public static int cmpl(int __a, int __b)
{
Assembly.breakpoint();
throw new todo.TODO();
if (SoftFloat.isNaN(__a) || SoftFloat.isNaN(__b))
return -1;
return SoftFloat.__cmp(__a, __b);
}
/**
* Compares two values.
* Compares two values, NaN returns {@code 1}.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2019/05/24
*/
@SuppressWarnings("SpellCheckingInspection")
public static int cmpg(int __a, int __b)
{
Assembly.breakpoint();
throw new todo.TODO();
if (SoftFloat.isNaN(__a) || SoftFloat.isNaN(__b))
return 1;
return SoftFloat.__cmp(__a, __b);
}
/**
......@@ -81,6 +129,18 @@ public class SoftFloat
throw new todo.TODO();
}
/**
* Is this Not a Number?
*
* @param __a The value to check.
* @return If this is not a number.
* @since 2021/04/07
*/
public static boolean isNaN(int __a)
{
return SoftFloat.NAN_MASK == (__a & SoftFloat.NAN_MASK);
}
/**
* Multiplies two values.
*
......@@ -91,8 +151,97 @@ public class SoftFloat
*/
public static float mul(int __a, int __b)
{
Assembly.breakpoint();
throw new todo.TODO();
// First value
boolean signA = SoftFloat.__signF32UI(__a);
int expA = SoftFloat.__expF32UI(__a);
int sigA = SoftFloat.__fracF32UI(__a);
// Second value
boolean signB = SoftFloat.__signF32UI(__b);
int expB = SoftFloat.__expF32UI(__b);
int sigB = SoftFloat.__fracF32UI(__b);
// Will this result in a negative value?
boolean signZ = signA ^ signB;
boolean returnInfinite = false;
int magBits = 0;
if (expA == 0xFF)
{
// if ( sigA || ((expB == 0xFF) && sigB) )
if (sigA != 0 || ((expB == 0xFF) && (sigB != 0)))
return Float.intBitsToFloat(
SoftFloat.__propagateNaNF32UI(__a, __b));
magBits = expB | sigB;
returnInfinite = true;
}
if (!returnInfinite && expB == 0xFF)
{
// if ( sigB )
if (sigB != 0)
return Float.intBitsToFloat(
SoftFloat.__propagateNaNF32UI(__a, __b));
magBits = expA | sigA;
returnInfinite = true;
}
// Returning infinite value?
if (returnInfinite)
{
// if ( ! magBits )
if (magBits == 0)
return SoftFloat.FLOAT_DEFAULT_NAN;
return Float.intBitsToFloat(
SoftFloat.__packToF32UI(signZ, 0xFF, 0));
}
// if ( ! expA )
if (expA == 0)
{
// if ( ! sigA )
if (sigA == 0)
return Float.intBitsToFloat(
SoftFloat.__packToF32UI(signZ, 0, 0));
long normExpSig = SoftFloat.__normSubnormalF32Sig(sigA);
expA = (short)Assembly.longUnpackHigh(normExpSig);
sigA = Assembly.longUnpackLow(normExpSig);
}
// if ( ! expB )
if (expB == 0)
{
// if ( ! sigB )
if (sigB == 0)
return Float.intBitsToFloat(
SoftFloat.__packToF32UI(signZ, 0, 0));
long normExpSig = SoftFloat.__normSubnormalF32Sig(sigB);
expB = (short)Assembly.longUnpackHigh(normExpSig);
sigB = Assembly.longUnpackLow(normExpSig);
}
int expZ = (short)(expA + expB - 0x7F);
sigA = (sigA | 0x0080_0000) << 7;
sigB = (sigB | 0x0080_0000) << 8;
// sigZ = softfloat_shortShiftRightJam64(
// (uint_fast64_t)sigA * sigB, 32); <-- unsigned multiply
int sigZ = (int)SoftFloat.__shortShiftRightJam64(
(sigA & 0xFFFF_FFFFL) * (sigB & 0xFFFF_FFFFL), 32);
// if ( sigZ < 0x40000000 )
if (UnsignedInteger.compareUnsigned(sigZ, 0x4000_0000) < 0)
{
expZ = (short)(expZ - 1);
sigZ <<= 1;
}
return Float.intBitsToFloat(
SoftFloat.__roundPackToF32(signZ, expZ, sigZ));
}
/**
......@@ -171,8 +320,21 @@ public class SoftFloat
*/
public static int toInteger(int __a)
{
Assembly.breakpoint();
throw new todo.TODO();
boolean sign = SoftFloat.__signF32UI(__a);
int exp = SoftFloat.__expF32UI(__a);
int sig = SoftFloat.__fracF32UI(__a);
if (exp != 0)
sig |= 0x0080_0000;
// sig64 = (uint_fast64_t) sig<<32;
long sig64 = Assembly.longPack(0, sig);
int shiftDist = 0xAA - exp;
if (UnsignedInteger.compareUnsigned(0, shiftDist) < 0)
sig64 = SoftFloat.__shiftRightJam64(sig64, shiftDist);
return SoftFloat.__roundToI32(sign, sig64);
}
/**
......@@ -187,5 +349,353 @@ public class SoftFloat
Assembly.breakpoint();
throw new todo.TODO();
}
}
/**
* Compares two values.
*
* @param __a A.
* @param __b B.
* @return The result.
* @since 2021/04/07
*/
private static int __cmp(int __a, int __b)
{
// Equality, note second means -0 == 0
// return (uiA == uiB) || ! (uint32_t) ((uiA | uiB)<<1);
if (__a == __b || ((__a | __b) << 1) == 0)
return 0;
// Less than
// (signA != signB) ? signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
// : (uiA != uiB) && (signA ^ (uiA < uiB));
boolean signA = (0 != (__a & SoftFloat.SIGN_MASK));
boolean signB = (0 != (__b & SoftFloat.SIGN_MASK));
if (signA != signB)
{
// signA && ((uint32_t) ((uiA | uiB)<<1) != 0)
if (signA && ((__a | __b) << 1) != 0)
return -1;
}
// (uiA != uiB) && (signA ^ (uiA < uiB))
// ^^^ const ^^
else if (signA ^ (UnsignedInteger.compareUnsigned(__a, __b) < 0))
return -1;
// Anything else assume greater than
return 1;
}
/**
* Returns the exponent.
*
* @param __a The float to read from.
* @return The exponent.
* @since 2021/04/10
*/
private static int __expF32UI(int __a)
{
// ((int_fast16_t) ((a)>>23) & 0xFF)
return (((__a) >>> SoftFloat._EXP_SHIFT) & 0xFF);
}
/**
* Returns the fraction/significand from the floating point value.
*
* @param __a The float to read from.
* @return The fraction/significand.
* @since 2021/04/10
*/
private static int __fracF32UI(int __a)
{
return (__a & SoftFloat.FRACTION_MASK);
}
/**
* Gets if this is a NaN.
*
* @param __a The value to check.
* @return If this is a NaN.
* @since 2021/04/10
*/
private static boolean __isNaNF32UI(int __a)
{
return ((~(__a) & 0x7F800000) == 0) &&
((__a) & 0x007FFFFF) != 0;
}
/**
* Gets if this is a signaling NaN.
*
* @param __a The value to check.
* @return If this is a signaling NaN.
* @since 2021/04/10
*/
private static boolean __isSigNaNF32UI(int __a)
{
return ((__a & 0x7FC00000) == 0x7F800000) &&
(__a & 0x003FFFFF) != 0;
}
/**
* Normalized round packed to 32-bit float.
*
* @param __sign The sign.
* @param __exp The exponent.
* @param __sig The significand.
* @return The resultant value.
* @since 2021/04/08
*/
protected static int __normRoundPackToF32(boolean __sign, int __exp,
int __sig)
{
int shiftDist;
// shiftDist = softfloat_countLeadingZeros32( __sig ) - 1;
shiftDist = Integer.numberOfLeadingZeros(__sig) - 1;
__exp -= shiftDist;
// if ( (7 <= shiftDist) && ((unsigned int) exp < 0xFD) ) {
if (7 <= shiftDist &&
UnsignedInteger.compareUnsigned(__exp, 0xFD) < 0)
{
// uZ.ui = packToF32UI( sign, sig ? exp : 0, sig<<(shiftDist - 7));
return SoftFloat.__packToF32UI(__sign,
(__sig != 0 ? __exp : 0),
__sig << (shiftDist - 7));
}
// return softfloat_roundPackToF32( sign, exp, sig<<shiftDist );
return SoftFloat.__roundPackToF32(__sign, __exp,
__sig << shiftDist);
}
/**
* Normalizes a subnormal 32-bit float significand.
*
* @param __sig The significand.
* @return The normalized value, the exponent is the high value and
* the significand is the low value.
* @since 2021/04/10
*/
private static long __normSubnormalF32Sig(int __sig)
{
// softfloat_countLeadingZeros32( sig ) - 8;
int shiftDist = Integer.numberOfLeadingZeros(__sig) - 8;
// struct exp16_sig32 { int_fast16_t exp; uint_fast32_t sig; };
// exp = 1 - shiftDist ,, sig = sig<<shiftDist
return Assembly.longPack(__sig << shiftDist,
(short)(1 - shiftDist));
}
/**
* Packs value to an unsigned integer, note that some of these values are
* perfectly fine to overflow into each other such as the significand
* being larger than the value.
*
* @param __sign Sign bit.
* @param __exp Exponent.
* @param __sig Significand.
* @return The packed value.