diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java index 7e61e34304..6b34dd3c10 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/floatformat/FloatFormat.java @@ -169,21 +169,6 @@ public class FloatFormat { return minValue; } - // Create a double given sign, 8-byte normalized mantissa, and unbiased scale - static double createDouble(boolean sgn, long mantissa, int scale) { - long exp = scale + 1023; - long bits = mantissa >>> 11;// 11 = 64 (long size) - 52 (frac size) - 1 (jbit)) - if (exp != 1) { // normal - bits &= 0xfffffffffffffL; - bits |= exp << 52; - } - - if (sgn) { - bits |= 0x8000000000000000L; - } - return Double.longBitsToDouble(bits); - } - FloatKind extractKind(long encoding) { int exp = extractExponentCode(encoding); if (exp == maxexponent) { @@ -252,8 +237,7 @@ public class FloatFormat { // set sign bit and return the result if size <= 8 private long setSign(long x, boolean sign) { - if (!sign) - { + if (!sign) { return x; // Assume bit is already zero } long mask = 1; @@ -288,8 +272,7 @@ public class FloatFormat { public BigFloat getBigZero(boolean sgn) { return new BigFloat(effective_frac_size, exp_size, FloatKind.FINITE, sgn ? -1 : +1, - BigInteger.ZERO, - 2 - (1 << (exp_size - 1))); + BigInteger.ZERO, 2 - (1 << (exp_size - 1))); } public BigInteger getBigInfinityEncoding(boolean sgn) { @@ -387,7 +370,7 @@ public class FloatFormat { int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); FloatKind kind = extractKind(encoding); - + int scale; long unscaled = frac; if (kind == FloatKind.FINITE) { @@ -410,6 +393,16 @@ public class FloatFormat { // Convert floating point encoding into host's double if size <= 8 public double decodeHostFloat(long encoding) { + + if (size == 8) { // assume IEEE-754 8-byte format which matches Java double encoding + return Double.longBitsToDouble(encoding); + } + + if (size > 8) { + throw new UnsupportedOperationException( + "method not supported for float size of " + size); + } + boolean sgn = extractSign(encoding); int exp = extractExponentCode(encoding); long frac = extractFractionalCode(encoding); @@ -428,15 +421,42 @@ public class FloatFormat { return Double.NaN; } - // Get unbiased scale and normalized mantissa exp -= bias; - long mantissa = frac << (8 * 8 - frac_size); - if (!subnormal && jbitimplied) { - mantissa >>= 1; // Make room for 1 jbit - mantissa |= 0x8000000000000000L; // set bit in at top of normalized frac + + long msbit = 1 << (frac_size - 1); // most-significant fractional/mantissa bit + + if (!subnormal && !jbitimplied) { + frac &= ~msbit; // remove explicit jbit + frac <<= 1; + --exp; } - return createDouble(sgn, mantissa, exp); + if (subnormal) { + // attempt to normalize + exp = -bias; + + while (exp > -1023 && (frac & msbit) == 0 && frac != 0) { + frac <<= 1; + --exp; + } + + // establish implied jbit + if (exp > -1023 && (frac & msbit) != 0 && frac != 0) { + frac <<= 1; + } + else { + --exp; + } + + // mask-off implied jbit + frac &= ~-(1 << frac_size); + } + + exp += 1023; + frac <<= 52 - frac_size; + + long encodedDouble = (sgn ? (1L << 63) : 0) | ((long) exp << 52) | frac; + return Double.longBitsToDouble(encodedDouble); } public BigFloat decodeBigFloat(BigInteger encoding) { @@ -1124,7 +1144,7 @@ public class FloatFormat { fa.round(); return getEncoding(fa); } - + public BigFloat getBigFloat(BigInteger value) { if (size == 8) { diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java index b789bcedaf..63e28b5259 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/pcode/floatformat/FloatFormatTest.java @@ -32,21 +32,6 @@ public class FloatFormatTest extends AbstractGenericTest { super(); } - @Test - public void testCreateFloat() { - int i = 0; - for (double x : BigFloatTest.testDoubleList) { - if (!Double.isFinite(x)) { - continue; - } - FloatFormat.SmallFloatData data = FloatFormat.getSmallFloatData(x); - double y = FloatFormat.createDouble(data.sign < 0, - data.unscaled << (64 - data.fracbits), data.scale); - Assert.assertEquals("case #" + Integer.toString(i), x, y, 0); - ++i; - } - } - @Test public void testGetEncodingMinval() { FloatFormat ff = new FloatFormat(4); @@ -269,6 +254,30 @@ public class FloatFormatTest extends AbstractGenericTest { Assert.assertEquals(intbits, encoding.longValue()); Assert.assertEquals(big, ff.decodeBigFloat(encoding)); + big = ff.getBigFloat(Float.MIN_VALUE); + encoding = ff.getEncoding(big); + intbits = Float.floatToRawIntBits(Float.MIN_VALUE); + Assert.assertEquals(intbits, encoding.longValue()); + Assert.assertEquals(Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0); + + big = ff.getBigFloat(Float.MAX_VALUE); + encoding = ff.getEncoding(big); + intbits = Float.floatToRawIntBits(Float.MAX_VALUE); + Assert.assertEquals(intbits, encoding.longValue()); + Assert.assertEquals(Float.MAX_VALUE, (float) ff.decodeHostFloat(intbits), 0); + + big = ff.getBigFloat(-Float.MIN_VALUE); + encoding = ff.getEncoding(big); + intbits = Float.floatToRawIntBits(-Float.MIN_VALUE); + Assert.assertEquals(intbits, (int) encoding.longValue()); + Assert.assertEquals(-Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0); + + big = ff.getBigFloat(-Float.MAX_VALUE); + encoding = ff.getEncoding(big); + intbits = Float.floatToRawIntBits(-Float.MAX_VALUE); + Assert.assertEquals(intbits, (int) encoding.longValue()); + Assert.assertEquals(-Float.MAX_VALUE, (float) ff.decodeHostFloat(intbits), 0); + f = 3.75f; intbits = Float.floatToRawIntBits(f); big = ff.getBigFloat(f); @@ -430,6 +439,12 @@ public class FloatFormatTest extends AbstractGenericTest { Assert.assertEquals(intbits, encoding); Assert.assertEquals(f, (float) ff.decodeHostFloat(encoding), 0); + intbits = 1; // smallest subnormal value + Assert.assertEquals(Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0); + + intbits = 0x80000001; // smallest subnormal value + Assert.assertEquals(-Float.MIN_VALUE, (float) ff.decodeHostFloat(intbits), 0); + f = 8.908155E-39f; intbits = Float.floatToRawIntBits(f); encoding = ff.getEncoding(f); @@ -1473,11 +1488,10 @@ public class FloatFormatTest extends AbstractGenericTest { doTestValueOfBigInteger(BigDecimal.valueOf(2.1234567890123456789e123)); doTestValueOfBigInteger(BigDecimal.valueOf(2.1234567890123456789e123).negate()); - + // NOTE: BigDecimal.valueOf(Double.MAX_VALUE) produces a value greater than Double.MAX_VALUE // doTestValueOfBigInteger(BigDecimal.valueOf(Double.MAX_VALUE)); - BigFloat bf = ff.decodeBigFloat(Double.doubleToRawLongBits(Double.MAX_VALUE)); bf = ff.getBigFloat(bf.toBigInteger()); assertEquals("1.797693134862316E+308", ff.toDecimalString(bf)); @@ -1640,14 +1654,12 @@ public class FloatFormatTest extends AbstractGenericTest { ff.toDecimalString(ff.decodeBigFloat(0x0065006700610050L))); assertEquals("2.123456789012346", ff.toDecimalString(ff.decodeBigFloat(0x4000FCD6E9BA37B3L))); - assertEquals("0.3", - ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L))); + assertEquals("0.3", ff.toDecimalString(ff.decodeBigFloat(0x3FD3333333333333L))); } @Test public void testFloatDecodeWithToString() { FloatFormat ff = FloatFormatFactory.getFloatFormat(4); - assertEquals("-1.4682312", - ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true)); + assertEquals("-1.4682312", ff.toDecimalString(ff.decodeBigFloat(0xbfbbef00L), true)); } }