Squelch Java use of HOST_FLOAT_WORDS_BIG_ENDIAN (take two)

Zack Weinberg zack@codesourcery.com
Thu Mar 13 21:12:00 GMT 2003


Revised patch which generates correct hex floating constants for
java.lang.Float and java.lang.Double.  I was not able to incorporate
Richard's suggestion to use __builtin_nan() in gcjh, because the C++
compiler currently rejects that construct.  We can revisit that after
the C++ compiler is fixed.

I also did my best to restore output of decimal floating point in
jcf-dump, however, it doesn't work; from

public class test {
  public static final double Pi 
      = 3.141592653589793116; // closest representable
};

I get

Field name:"Pi" public static final Signature: 6=double
Attribute "ConstantValue", length:2, value: #8=<Double 2.283185307179586232>

Assistance would be appreciated.  (The .class file itself, and the .h
file produced by gcjh, are correct.)

I'm omitting the configure changes from this message since they need
no revision.

zw

        * javaop.h (jfloat, jdouble): Make them structures mirroring
        the bit fields of IEEE float and double respectively.
        (JFLOAT_FINITE, JFLOAT_QNAN_MASK, JFLOAT_EXP_BIAS,
        JDOUBLE_FINITE, JDOUBLE_QNAN_MASK, JDOUBLE_EXP_BIAS): New.
        (union Word, union DWord): Delete.
        (WORD_TO_FLOAT, WORDS_TO_DOUBLE): Update to match.

        * gjavah.c (java_float_finite, java_double_finite, F_NAN_MASK,
        D_NAN_MASK): Delete.
        (jni_print_float, jni_print_double): New.  Generate
        hexadecimal floating constants.
        (print_field_info): Use jni_print_float/double.

        * jcf-dump.c: Include math.h.  Use ldexp/frexp to assemble
        finite floating point numbers for output; special case
        non-finite floats.

===================================================================
Index: javaop.h
--- javaop.h	18 Jan 2003 22:15:51 -0000	1.13
+++ javaop.h	13 Mar 2003 21:12:07 -0000
@@ -55,21 +55,26 @@ typedef int32                   jint;
 typedef int64                   jlong;
 typedef void*                   jref;
 
-/* A 32-bit IEEE single-precision float. */
-#ifndef jfloat 
-#define jfloat float
-#endif
-
-/* A 32-bit IEEE double-precision float. */
-#ifndef jdouble
-#define jdouble double
-#endif
-
-union Word {
-  jint i;
-  jfloat f;
-  void *p;
-};
+/* A 32-bit big-endian IEEE single-precision float. */
+typedef struct _jfloat {
+  unsigned int negative : 1;
+  unsigned int exponent : 8;
+  unsigned int mantissa : 23;
+} jfloat;
+#define JFLOAT_FINITE(f) ((f).exponent != 0xFF)
+#define JFLOAT_QNAN_MASK 0x400000
+#define JFLOAT_EXP_BIAS 0x7f
+
+/* A 32-bit big-endian IEEE double-precision float. */
+typedef struct _jdouble {
+  unsigned int negative : 1;
+  unsigned int exponent : 11;
+  unsigned int mantissa0: 20;
+  unsigned int mantissa1: 32;
+} jdouble;
+#define JDOUBLE_FINITE(f) ((f).exponent != 0x7FF)
+#define JDOUBLE_QNAN_MASK 0x80000  /* apply to mantissa0 */
+#define JDOUBLE_EXP_BIAS 0x3ff
 
 /* A jword is an unsigned integral type big enough for a 32-bit jint
    or jfloat *or* a pointer.  It is the type appropriate for stack
@@ -102,9 +107,14 @@ union Word {
 
 static inline jfloat
 WORD_TO_FLOAT(jword w)
-{ union Word wu;
-  wu.i = w;
-  return wu.f;
+{
+  jfloat f;
+
+  f.negative = (w & 0x80000000) >> 31;
+  f.exponent = (w & 0x7f800000) >> 23;
+  f.mantissa = (w & 0x007fffff);
+
+  return f;
 } 
 
 /* Sign extend w.  If the host on which this cross-compiler runs uses
@@ -126,21 +136,17 @@ WORDS_TO_LONG(jword hi, jword lo)
   return ((jlong) hi << 32) | ((jlong)lo & (((jlong)1 << 32) -1));
 }
 
-union DWord {
-  jdouble d;
-  jlong l;
-  jword w[2];
-};
-
 static inline jdouble
 WORDS_TO_DOUBLE(jword hi, jword lo)
-{ union DWord wu;
-#if (1 == HOST_FLOAT_WORDS_BIG_ENDIAN)
-  wu.l = WORDS_TO_LONG(lo, hi);
-#else
-  wu.l = WORDS_TO_LONG(hi, lo);
-#endif
-  return wu.d;
+{
+  jdouble d;
+
+  d.negative  = (hi & 0x80000000) >> 31;
+  d.exponent  = (hi & 0x7ff00000) >> 20;
+  d.mantissa0 = (hi & 0x000fffff);
+  d.mantissa1 = lo;
+
+  return d;
 } 
 
 /* If PREFIX_CHAR is the first character of the Utf8 encoding of a character,
===================================================================
Index: gjavah.c
--- gjavah.c	12 Mar 2003 16:14:01 -0000	1.105
+++ gjavah.c	13 Mar 2003 21:07:09 -0000
@@ -134,8 +134,6 @@ static void print_full_cxx_name (FILE*, 
 static void decompile_method (FILE*, JCF*, int);
 static void add_class_decl (FILE*, JCF*, JCF_u2);
 
-static int java_float_finite (jfloat);
-static int java_double_finite (jdouble);
 static void print_name (FILE *, JCF *, int);
 static void print_base_classname (FILE *, JCF *, int);
 static int utf8_cmp (const unsigned char *, int, const char *);
@@ -158,6 +156,8 @@ static void version (void) ATTRIBUTE_NOR
 static int overloaded_jni_method_exists_p (const unsigned char *, int,
 					   const char *, int);
 static void jni_print_char (FILE *, int);
+static void jni_print_float (FILE *, jfloat);
+static void jni_print_double (FILE *, jdouble);
 static void decompile_return_statement (FILE *, JCF *, int, int, int);
 
 JCF_u2 current_field_name;
@@ -247,36 +247,54 @@ static int decompiled = 0;
 
 #include "jcf-reader.c"
 
-/* Some useful constants.  */
-#define F_NAN_MASK 0x7f800000
-#if (1 == HOST_FLOAT_WORDS_BIG_ENDIAN) && ! defined (HOST_WORDS_BIG_ENDIAN)
-#define D_NAN_MASK 0x000000007ff00000LL
-#else
-#define D_NAN_MASK 0x7ff0000000000000LL
-#endif
-
-/* Return 1 if F is not Inf or NaN.  */
-static int
-java_float_finite (jfloat f)
+/* Print a single-precision float, suitable for parsing by g++.  */
+static void
+jni_print_float (FILE *stream, jfloat f)
 {
-  union Word u;
-  u.f = f;
-
-  /* We happen to know that F_NAN_MASK will match all NaN values, and
-     also positive and negative infinity.  That's why we only need one
-     test here.  See The Java Language Specification, section 20.9.  */
-  return (u.i & F_NAN_MASK) != F_NAN_MASK;
+  /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
+     work in data initializers.  FIXME.  */
+  if (JFLOAT_FINITE (f))
+    {
+      fputs (" = ", stream);
+      if (f.negative)
+	putc ('-', stream);
+      if (f.exponent)
+	fprintf (stream, "0x1.%.6xp%+df",
+		 ((unsigned int)f.mantissa) << 1,
+		 f.exponent - JFLOAT_EXP_BIAS);
+      else
+	/* Exponent of 0x01 is -125; exponent of 0x00 is *also* -125,
+	   because the implicit leading 1 bit is no longer present.  */
+	fprintf (stream, "0x0.%.6xp%+df",
+		 ((unsigned int)f.mantissa) << 1,
+		 f.exponent + 1 - JFLOAT_EXP_BIAS);
+    }
+  fputs (";\n", stream);
 }
 
-/* Return 1 if D is not Inf or NaN.  */
-static int
-java_double_finite (jdouble d)
+/* Print a double-precision float, suitable for parsing by g++.  */
+static void
+jni_print_double (FILE *stream, jdouble f)
 {
-  union DWord u;
-  u.d = d;
-
-  /* Now check for all NaNs.  */
-  return (u.l & D_NAN_MASK) != D_NAN_MASK;
+  /* It'd be nice to use __builtin_nan/__builtin_inf here but they don't
+     work in data initializers.  FIXME.  */
+  if (JDOUBLE_FINITE (f))
+    {
+      fputs (" = ", stream);
+      if (f.negative)
+	putc ('-', stream);
+      if (f.exponent)
+	fprintf (stream, "0x1.%.5x%.8xp%+d",
+		 f.mantissa0, f.mantissa1,
+		 f.exponent - JDOUBLE_EXP_BIAS);
+      else
+	/* Exponent of 0x001 is -1022; exponent of 0x000 is *also* -1022,
+	   because the implicit leading 1 bit is no longer present.  */
+	fprintf (stream, "0x0.%.5x%.8xp%+d",
+		 f.mantissa0, f.mantissa1,
+		 f.exponent + 1 - JDOUBLE_EXP_BIAS);
+    }
+  fputs (";\n", stream);
 }
 
 /* Print a character, appropriately mangled for JNI.  */
@@ -732,10 +750,7 @@ print_field_info (FILE *stream, JCF* jcf
 		jfloat fnum = JPOOL_FLOAT (jcf, current_field_value);
 		fputs ("const jfloat ", out);
 		print_field_name (out, jcf, name_index, 0);
-		if (! java_float_finite (fnum))
-		  fputs (";\n", out);
-		else
-		  fprintf (out, " = %.10g;\n",  fnum);
+		jni_print_float (out, fnum);
 	      }
 	      break;
 	    case CONSTANT_Double:
@@ -743,10 +758,7 @@ print_field_info (FILE *stream, JCF* jcf
 		jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value);
 		fputs ("const jdouble ", out);
 		print_field_name (out, jcf, name_index, 0);
-		if (! java_double_finite (dnum))
-		  fputs (";\n", out);
-		else
-		  fprintf (out, " = %.17g;\n",  dnum);
+		jni_print_double (out, dnum);
 	      }
 	      break;
 	    default:
===================================================================
Index: jcf-dump.c
--- jcf-dump.c	18 Jan 2003 22:15:51 -0000	1.55
+++ jcf-dump.c	13 Mar 2003 21:07:10 -0000
@@ -62,6 +62,7 @@ The Free Software Foundation is independ
 #include "version.h"
 
 #include <getopt.h>
+#include <math.h>
 
 /* Outout file. */
 FILE *out;
@@ -504,24 +505,67 @@ print_constant (FILE *out, JCF *jcf, int
       break;
     case CONSTANT_Float:
       {
-	union
-	{
-	  jfloat f;
-	  int32 i;
-	} pun;
-	
-	pun.f = JPOOL_FLOAT (jcf, index);
-	fprintf (out, "%s%.10g",
-		 verbosity > 0 ? "Float " : "", (double) pun.f);
+	jfloat fnum = JPOOL_FLOAT (jcf, index);
+
+	if (verbosity > 0)
+	  fputs ("Float ", out);
+
+	if (fnum.negative)
+	  putc ('-', out);
+
+	if (JFLOAT_FINITE (fnum))
+	  {
+	    int dummy;
+	    double f = frexp (fnum.mantissa, &dummy);
+	    f = ldexp (f, fnum.exponent - JFLOAT_EXP_BIAS + 1);
+	    fprintf (out, "%.10g", f);
+	  }
+	else
+	  {
+	    if (fnum.mantissa == 0)
+	      fputs ("Inf", out);
+	    else if (fnum.mantissa & JFLOAT_QNAN_MASK)
+	      fprintf (out, "QNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
+	    else
+	      fprintf (out, "SNaN(%u)", (fnum.mantissa & ~JFLOAT_QNAN_MASK));
+	  }
+
 	if (verbosity > 1)
-	  fprintf (out, ", bits = 0x%08lx", (long) pun.i);
+	  fprintf (out, ", bits = 0x%08lx", JPOOL_UINT (jcf, index));
 	
 	break;
       }
     case CONSTANT_Double:
       {
 	jdouble dnum = JPOOL_DOUBLE (jcf, index);
-	fprintf (out, "%s%.20g", verbosity > 0 ? "Double " : "", dnum);
+
+	if (verbosity > 0)
+	  fputs ("Double ", out);
+
+	if (dnum.negative)
+	  putc ('-', out);
+
+	if (JDOUBLE_FINITE (dnum))
+	  {
+	    int dummy;
+	    uint64 mantissa = ((((uint64) dnum.mantissa0) << 32)
+			       + dnum.mantissa1);
+	    double d = frexp (mantissa, &dummy);
+	    d = ldexp (d, dnum.exponent - JDOUBLE_EXP_BIAS + 1);
+	    fprintf (out, "%.20g", d);
+	  }
+	else
+	  {
+	    uint64 mantissa = dnum.mantissa0 & ~JDOUBLE_QNAN_MASK;
+	    mantissa = (mantissa << 32) + dnum.mantissa1;
+
+	    if (dnum.mantissa0 == 0 && dnum.mantissa1 == 0)
+	      fputs ("Inf", out);
+	    else if (dnum.mantissa0 & JDOUBLE_QNAN_MASK)
+	      fprintf (out, "QNaN(%llu)", (unsigned long long)mantissa);
+	    else
+	      fprintf (out, "SNaN(%llu)", (unsigned long long)mantissa);
+	  }
 	if (verbosity > 1)
 	  {
 	    int32 hi, lo;



More information about the Java-patches mailing list