[llvm-commits] [llvm-gcc-4.2] r99068 - /llvm-gcc-4.2/trunk/gcc/real.c

Anton Korobeynikov asl at math.spbu.ru
Sat Mar 20 12:21:00 PDT 2010


Author: asl
Date: Sat Mar 20 14:21:00 2010
New Revision: 99068

URL: http://llvm.org/viewvc/llvm-project?rev=99068&view=rev
Log:
Add conversion routines for half precision fp

Modified:
    llvm-gcc-4.2/trunk/gcc/real.c

Modified: llvm-gcc-4.2/trunk/gcc/real.c
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/real.c?rev=99068&r1=99067&r2=99068&view=diff
==============================================================================
--- llvm-gcc-4.2/trunk/gcc/real.c (original)
+++ llvm-gcc-4.2/trunk/gcc/real.c Sat Mar 20 14:21:00 2010
@@ -3817,10 +3817,129 @@
 
 /* LLVM LOCAL begin */
 /* IEEE half precision format. */
+
+static void encode_ieee_half (const struct real_format *fmt,
+			      long *, const REAL_VALUE_TYPE *);
+static void decode_ieee_half (const struct real_format *,
+			      REAL_VALUE_TYPE *, const long *);
+
+static void
+encode_ieee_half (const struct real_format *fmt, long *buf,
+		  const REAL_VALUE_TYPE *r)
+{
+  unsigned long image, sig, exp;
+  unsigned long sign = r->sign;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
+
+  image = sign << 15;
+  sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 11)) & 0x3ff;
+
+  switch (r->cl)
+    {
+    case rvc_zero:
+      break;
+
+    case rvc_inf:
+      if (fmt->has_inf)
+	image |= 31 << 10;
+      else
+	image |= 0x7fff;
+      break;
+
+    case rvc_nan:
+      if (fmt->has_nans)
+	{
+	  if (r->canonical)
+	    sig = 0;
+	  if (r->signalling == fmt->qnan_msb_set)
+	    sig &= ~(1 << 9);
+	  else
+	    sig |= 1 << 9;
+	  if (r->canonical && !fmt->qnan_msb_set)
+	    sig |= (1 << 9) - 1;
+	  else if (sig == 0)
+	    sig = 1 << 8;
+
+	  image |= 31 << 10;
+	  image |= sig;
+	}
+      else
+	image |= 0x3ff;
+      break;
+
+    case rvc_normal:
+      /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+	 whereas the intermediate representation is 0.F x 2**exp.
+	 Which means we're off by one.  */
+      if (denormal)
+	exp = 0;
+      else
+	exp = REAL_EXP (r) + 15 - 1;
+      image |= exp << 10;
+      image |= sig;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  buf[0] = image;
+}
+
+static void
+decode_ieee_half (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+		  const long *buf)
+{
+  unsigned long image = buf[0] & 0xffff;
+  bool sign = (image >> 15) & 1;
+  int exp = (image >> 10) & 0x1f;
+
+  memset (r, 0, sizeof (*r));
+  image <<= HOST_BITS_PER_LONG - 11;
+  image &= ~SIG_MSB;
+
+  if (exp == 0)
+    {
+      if (image && fmt->has_denorm)
+	{
+	  r->cl = rvc_normal;
+	  r->sign = sign;
+	  SET_REAL_EXP (r, -14);
+	  r->sig[SIGSZ-1] = image << 1;
+	  normalize (r);
+	}
+      else if (fmt->has_signed_zero)
+	r->sign = sign;
+    }
+  else if (exp == 31 && (fmt->has_nans || fmt->has_inf))
+    {
+      if (image)
+	{
+	  r->cl = rvc_nan;
+	  r->sign = sign;
+	  r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+			   ^ fmt->qnan_msb_set);
+	  r->sig[SIGSZ-1] = image;
+	}
+      else
+	{
+	  r->cl = rvc_inf;
+	  r->sign = sign;
+	}
+    }
+  else
+    {
+      r->cl = rvc_normal;
+      r->sign = sign;
+      SET_REAL_EXP (r, exp - 15 + 1);
+      r->sig[SIGSZ-1] = image | SIG_MSB;
+    }
+}
+
 const struct real_format ieee_half_format =
   {
-    NULL,
-    NULL,
+    encode_ieee_half,
+    decode_ieee_half,
     2,
     1,
     11,





More information about the llvm-commits mailing list