Logo Search packages:      
Sourcecode: pcc version File versions  Download package

softfloat.c

/*    $Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $      */

/*
 * Copyright (c) 2008 Anders Magnusson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifdef SOFTFLOAT

#include "pass1.h"


/*
 * Floating point emulation to be used when cross-compiling.
 * Currently only supports F- and D-float, used in DEC machines.
 * Should be trivial to add other emulations.
 *
 * XXX - assumes that:
 *    - long long is (at least) 64 bits
 *    - int is at least 32 bits.
 *    - short is 16 bits.
 */

#ifdef FDFLOAT

/*
 * Useful macros to manipulate the float.
 */
#define DSIGN(w)  (((w).fd1 >> 15) & 1)
#define DSIGNSET(w,s)   ((w).fd1 = (s << 15) | ((w).fd1 & 077777))
#define DEXP(w)         (((w).fd1 >> 7) & 0377)
#define DEXPSET(w,e)    ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177))
#define DMANTH(w) ((w).fd1 & 0177)
#define DMANTHSET(w,m)  ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600))

typedef unsigned int lword;
typedef unsigned long long dword;

#define MAXMANT 0x100000000000000LL

/*
 * Returns a zero dfloat.
 */
static SF
nulldf(void)
{
      SF rv;

      rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0;
      return rv;
}

/*
 * Convert a (u)longlong to dfloat.
 * XXX - fails on too large (> 55 bits) numbers.
 */
SF
soft_cast(CONSZ ll, TWORD t)
{
      int i;
      SF rv;

      rv = nulldf();
      if (ll == 0)
            return rv;  /* fp is zero */
      if (ll < 0)
            DSIGNSET(rv,1), ll = -ll;
      for (i = 0; ll > 0; i++, ll <<= 1)
            ;
      DEXPSET(rv, 192-i);
      DMANTHSET(rv, ll >> 56);
      rv.fd2 = ll >> 40;
      rv.fd3 = ll >> 24;
      rv.fd4 = ll >> 8;
      return rv;
}

/*
 * multiply two dfloat. Use chop, not round.
 */
SF
soft_mul(SF p1, SF p2)
{
      SF rv;
      lword a1[2], a2[2], res[4];
      dword sum;

      res[0] = res[1] = res[2] = res[3] = 0;

      /* move mantissa into lwords */
      a1[0] = p1.fd4 | (p1.fd3 << 16);
      a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000;

      a2[0] = p2.fd4 | (p2.fd3 << 16);
      a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000;

#define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \
      res[r] = sum; sum >>= 32;

      sum = 0;
      MULONE(0, 0, 0);
      MULONE(1, 0, 1);
      res[2] = sum;
      sum = 0;
      MULONE(0, 1, 1);
      MULONE(1, 1, 2);
      res[3] = sum;

      rv.fd1 = 0;
      DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2));
      DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128);
      if (res[3] & 0x8000) {
            res[3] = (res[3] << 8) | (res[2] >> 24);
            res[2] = (res[2] << 8) | (res[1] >> 24);
      } else {
            DEXPSET(rv, DEXP(rv) - 1);
            res[3] = (res[3] << 9) | (res[2] >> 23);
            res[2] = (res[2] << 9) | (res[1] >> 23);
      }
      DMANTHSET(rv, res[3] >> 16);
      rv.fd2 = res[3];
      rv.fd3 = res[2] >> 16;
      rv.fd4 = res[2];
      return rv;
}

SF
soft_div(SF t, SF n)
{
      SF rv;
      dword T, N, K;
      int c;

#define SHL(x,b) ((dword)(x) << b)
      T = SHL(1,55) | SHL(DMANTH(t), 48) |
          SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4;
      N = SHL(1,55) | SHL(DMANTH(n), 48) |
          SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4;

      c = T > N;
      for (K = 0; (K & 0x80000000000000ULL) == 0; ) {
            if (T >= N) {
                  T -= N;
                  K |= 1;
            }
            T <<= 1;
            K <<= 1;
      }
      rv.fd1 = 0;
      DSIGNSET(rv, DSIGN(t) ^ DSIGN(n));
      DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c);
      DMANTHSET(rv, K >> 48);
      rv.fd2 = K >> 32;
      rv.fd3 = K >> 16;
      rv.fd4 = K;
      return rv;
}

/*
 * Negate a float number. Easy.
 */
SF
soft_neg(SF sf)
{
      int sign = DSIGN(sf) == 0;
      DSIGNSET(sf, sign);
      return sf;
}

/*
 * Return true if fp number is zero.
 */
int
soft_isz(SF sf)
{
      return (DEXP(sf) == 0);
}

int
soft_cmp_eq(SF x1, SF x2)
{
      cerror("soft_cmp_eq");
      return 0;
}

int
soft_cmp_ne(SF x1, SF x2)
{
      cerror("soft_cmp_ne");
      return 0;
}

int
soft_cmp_le(SF x1, SF x2)
{
      cerror("soft_cmp_le");
      return 0;
}

int
soft_cmp_lt(SF x1, SF x2)
{
      cerror("soft_cmp_lt");
      return 0;
}

int
soft_cmp_ge(SF x1, SF x2)
{
      cerror("soft_cmp_ge");
      return 0;
}

int
soft_cmp_gt(SF x1, SF x2)
{
      cerror("soft_cmp_gt");
      return 0;
}

/*
 * Convert a fp number to a CONSZ.
 */
CONSZ
soft_val(SF sf)
{
      CONSZ mant;
      int exp = DEXP(sf) - 128;

      mant = SHL(1,55) | SHL(DMANTH(sf), 48) |
            SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4;

      while (exp < 0)
            mant >>= 1, exp++;
      while (exp > 0)
            mant <<= 1, exp--;
      return mant;
}

SF
soft_plus(SF x1, SF x2)
{
      cerror("soft_plus");
      return x1;
}

SF
soft_minus(SF x1, SF x2)
{
      cerror("soft_minus");
      return x1;
}

/*
 * Convert a hex constant to floating point number.
 */
NODE *
fhexcon(char *s)
{
      cerror("fhexcon");
      return NULL;
}

/*
 * Convert a floating-point constant to D-float and store it in a NODE.
 */
NODE *
floatcon(char *s)
{
      NODE *p;
      dword mant;
      SF fl, flexp, exp5;
      int exp, negexp, bexp;

      exp = 0;
      mant = 0;
#define ADDTO(sum, val) sum = sum * 10 + val - '0'
      for (; *s >= '0' && *s <= '9'; s++) {
            if (mant<MAXMANT)
                  ADDTO(mant, *s);
            else
                  exp++;
      }
      if (*s == '.') {
            for (s++; *s >= '0' && *s <= '9'; s++) {
                  if (mant<MAXMANT) {
                        ADDTO(mant, *s);
                        exp--;
                  }
            }
      }

      if ((*s == 'E') || (*s == 'e')) {
            int eexp = 0, sign = 0;
            s++;
            if (*s == '+')
                  s++;
            else if (*s=='-')
                  sign = 1, s++;

            for (; *s >= '0' && *s <= '9'; s++)
                  ADDTO(eexp, *s);
            if (sign)
                  eexp = -eexp;
            exp = exp + eexp;
      }

      negexp = 1;
      if (exp<0) {
            negexp = -1;
            exp = -exp;
      }


      flexp = soft_cast(1, INT);
      exp5 = soft_cast(5, INT);
      bexp = exp;
      fl = soft_cast(mant, INT);

      for (; exp; exp >>= 1) {
            if (exp&01)
                  flexp = soft_mul(flexp, exp5);
            exp5 = soft_mul(exp5, exp5);
      }
      if (negexp<0)
            fl = soft_div(fl, flexp);
      else
            fl = soft_mul(fl, flexp);

      DEXPSET(fl, DEXP(fl) + negexp*bexp);
      p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */
      p->n_dcon = fl;
      return p;
}
#else
#error missing softfloat definition
#endif
#endif

Generated by  Doxygen 1.6.0   Back to index