github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/vlrt_386.c (about)

     1  // Inferno's libkern/vlrt-386.c
     2  // http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
     3  //
     4  //         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
     6  //         Portions Copyright 2009 The Go Authors. All rights reserved.
     7  //
     8  // Permission is hereby granted, free of charge, to any person obtaining a copy
     9  // of this software and associated documentation files (the "Software"), to deal
    10  // in the Software without restriction, including without limitation the rights
    11  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    12  // copies of the Software, and to permit persons to whom the Software is
    13  // furnished to do so, subject to the following conditions:
    14  //
    15  // The above copyright notice and this permission notice shall be included in
    16  // all copies or substantial portions of the Software.
    17  //
    18  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    19  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    20  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    21  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    22  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    24  // THE SOFTWARE.
    25  
    26  /*
    27   * C runtime for 64-bit divide, others.
    28   *
    29   * TODO(rsc): The simple functions are dregs--8c knows how
    30   * to generate the code directly now.  Find and remove.
    31   */
    32  
    33  typedef	unsigned long	ulong;
    34  typedef	unsigned int	uint;
    35  typedef	unsigned short	ushort;
    36  typedef	unsigned char	uchar;
    37  typedef	signed char	schar;
    38  
    39  #define	SIGN(n)	(1UL<<(n-1))
    40  
    41  typedef	struct	Vlong	Vlong;
    42  struct	Vlong
    43  {
    44  	union
    45  	{
    46  		long long	v;
    47  		struct
    48  		{
    49  			ulong	lo;
    50  			ulong	hi;
    51  		};
    52  		struct
    53  		{
    54  			ushort	lols;
    55  			ushort	loms;
    56  			ushort	hils;
    57  			ushort	hims;
    58  		};
    59  	};
    60  };
    61  
    62  void	runtime·abort(void);
    63  
    64  void
    65  _d2v(Vlong *y, double d)
    66  {
    67  	union { double d; struct Vlong; } x;
    68  	ulong xhi, xlo, ylo, yhi;
    69  	int sh;
    70  
    71  	x.d = d;
    72  
    73  	xhi = (x.hi & 0xfffff) | 0x100000;
    74  	xlo = x.lo;
    75  	sh = 1075 - ((x.hi >> 20) & 0x7ff);
    76  
    77  	ylo = 0;
    78  	yhi = 0;
    79  	if(sh >= 0) {
    80  		/* v = (hi||lo) >> sh */
    81  		if(sh < 32) {
    82  			if(sh == 0) {
    83  				ylo = xlo;
    84  				yhi = xhi;
    85  			} else {
    86  				ylo = (xlo >> sh) | (xhi << (32-sh));
    87  				yhi = xhi >> sh;
    88  			}
    89  		} else {
    90  			if(sh == 32) {
    91  				ylo = xhi;
    92  			} else
    93  			if(sh < 64) {
    94  				ylo = xhi >> (sh-32);
    95  			}
    96  		}
    97  	} else {
    98  		/* v = (hi||lo) << -sh */
    99  		sh = -sh;
   100  		if(sh <= 10) {
   101  			ylo = xlo << sh;
   102  			yhi = (xhi << sh) | (xlo >> (32-sh));
   103  		} else {
   104  			/* overflow */
   105  			yhi = d;	/* causes something awful */
   106  		}
   107  	}
   108  	if(x.hi & SIGN(32)) {
   109  		if(ylo != 0) {
   110  			ylo = -ylo;
   111  			yhi = ~yhi;
   112  		} else
   113  			yhi = -yhi;
   114  	}
   115  
   116  	y->hi = yhi;
   117  	y->lo = ylo;
   118  }
   119  
   120  void
   121  _f2v(Vlong *y, float f)
   122  {
   123  
   124  	_d2v(y, f);
   125  }
   126  
   127  double
   128  _v2d(Vlong x)
   129  {
   130  	if(x.hi & SIGN(32)) {
   131  		if(x.lo) {
   132  			x.lo = -x.lo;
   133  			x.hi = ~x.hi;
   134  		} else
   135  			x.hi = -x.hi;
   136  		return -((long)x.hi*4294967296. + x.lo);
   137  	}
   138  	return (long)x.hi*4294967296. + x.lo;
   139  }
   140  
   141  float
   142  _v2f(Vlong x)
   143  {
   144  	return _v2d(x);
   145  }
   146  
   147  ulong	_div64by32(Vlong, ulong, ulong*);
   148  void	_mul64by32(Vlong*, Vlong, ulong);
   149  
   150  static void
   151  slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
   152  {
   153  	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
   154  	int i;
   155  
   156  	numhi = num.hi;
   157  	numlo = num.lo;
   158  	denhi = den.hi;
   159  	denlo = den.lo;
   160  
   161  	/*
   162  	 * get a divide by zero
   163  	 */
   164  	if(denlo==0 && denhi==0) {
   165  		numlo = numlo / denlo;
   166  	}
   167  
   168  	/*
   169  	 * set up the divisor and find the number of iterations needed
   170  	 */
   171  	if(numhi >= SIGN(32)) {
   172  		quohi = SIGN(32);
   173  		quolo = 0;
   174  	} else {
   175  		quohi = numhi;
   176  		quolo = numlo;
   177  	}
   178  	i = 0;
   179  	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
   180  		denhi = (denhi<<1) | (denlo>>31);
   181  		denlo <<= 1;
   182  		i++;
   183  	}
   184  
   185  	quohi = 0;
   186  	quolo = 0;
   187  	for(; i >= 0; i--) {
   188  		quohi = (quohi<<1) | (quolo>>31);
   189  		quolo <<= 1;
   190  		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
   191  			t = numlo;
   192  			numlo -= denlo;
   193  			if(numlo > t)
   194  				numhi--;
   195  			numhi -= denhi;
   196  			quolo |= 1;
   197  		}
   198  		denlo = (denlo>>1) | (denhi<<31);
   199  		denhi >>= 1;
   200  	}
   201  
   202  	if(q) {
   203  		q->lo = quolo;
   204  		q->hi = quohi;
   205  	}
   206  	if(r) {
   207  		r->lo = numlo;
   208  		r->hi = numhi;
   209  	}
   210  }
   211  
   212  static void
   213  dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
   214  {
   215  	ulong n;
   216  	Vlong x, q, r;
   217  
   218  	if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
   219  		if(qp) {
   220  			qp->hi = 0;
   221  			qp->lo = 0;
   222  		}
   223  		if(rp) {
   224  			rp->hi = num.hi;
   225  			rp->lo = num.lo;
   226  		}
   227  		return;
   228  	}
   229  
   230  	if(den.hi != 0){
   231  		q.hi = 0;
   232  		n = num.hi/den.hi;
   233  		_mul64by32(&x, den, n);
   234  		if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
   235  			slowdodiv(num, den, &q, &r);
   236  		else {
   237  			q.lo = n;
   238  			r.v = num.v - x.v;
   239  		}
   240  	} else {
   241  		if(num.hi >= den.lo){
   242  			q.hi = n = num.hi/den.lo;
   243  			num.hi -= den.lo*n;
   244  		} else {
   245  			q.hi = 0;
   246  		}
   247  		q.lo = _div64by32(num, den.lo, &r.lo);
   248  		r.hi = 0;
   249  	}
   250  	if(qp) {
   251  		qp->lo = q.lo;
   252  		qp->hi = q.hi;
   253  	}
   254  	if(rp) {
   255  		rp->lo = r.lo;
   256  		rp->hi = r.hi;
   257  	}
   258  }
   259  
   260  void
   261  _divvu(Vlong *q, Vlong n, Vlong d)
   262  {
   263  
   264  	if(n.hi == 0 && d.hi == 0) {
   265  		q->hi = 0;
   266  		q->lo = n.lo / d.lo;
   267  		return;
   268  	}
   269  	dodiv(n, d, q, 0);
   270  }
   271  
   272  void
   273  runtime·uint64div(Vlong n, Vlong d, Vlong q)
   274  {
   275  	_divvu(&q, n, d);
   276  }
   277  
   278  void
   279  _modvu(Vlong *r, Vlong n, Vlong d)
   280  {
   281  
   282  	if(n.hi == 0 && d.hi == 0) {
   283  		r->hi = 0;
   284  		r->lo = n.lo % d.lo;
   285  		return;
   286  	}
   287  	dodiv(n, d, 0, r);
   288  }
   289  
   290  void
   291  runtime·uint64mod(Vlong n, Vlong d, Vlong q)
   292  {
   293  	_modvu(&q, n, d);
   294  }
   295  
   296  static void
   297  vneg(Vlong *v)
   298  {
   299  
   300  	if(v->lo == 0) {
   301  		v->hi = -v->hi;
   302  		return;
   303  	}
   304  	v->lo = -v->lo;
   305  	v->hi = ~v->hi;
   306  }
   307  
   308  void
   309  _divv(Vlong *q, Vlong n, Vlong d)
   310  {
   311  	long nneg, dneg;
   312  
   313  	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
   314  		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
   315  			// special case: 32-bit -0x80000000 / -1 causes divide error,
   316  			// but it's okay in this 64-bit context.
   317  			q->lo = 0x80000000;
   318  			q->hi = 0;
   319  			return;
   320  		}
   321  		q->lo = (long)n.lo / (long)d.lo;
   322  		q->hi = ((long)q->lo) >> 31;
   323  		return;
   324  	}
   325  	nneg = n.hi >> 31;
   326  	if(nneg)
   327  		vneg(&n);
   328  	dneg = d.hi >> 31;
   329  	if(dneg)
   330  		vneg(&d);
   331  	dodiv(n, d, q, 0);
   332  	if(nneg != dneg)
   333  		vneg(q);
   334  }
   335  
   336  void
   337  runtime·int64div(Vlong n, Vlong d, Vlong q)
   338  {
   339  	_divv(&q, n, d);
   340  }
   341  
   342  void
   343  _modv(Vlong *r, Vlong n, Vlong d)
   344  {
   345  	long nneg, dneg;
   346  
   347  	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
   348  		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
   349  			// special case: 32-bit -0x80000000 % -1 causes divide error,
   350  			// but it's okay in this 64-bit context.
   351  			r->lo = 0;
   352  			r->hi = 0;
   353  			return;
   354  		}
   355  		r->lo = (long)n.lo % (long)d.lo;
   356  		r->hi = ((long)r->lo) >> 31;
   357  		return;
   358  	}
   359  	nneg = n.hi >> 31;
   360  	if(nneg)
   361  		vneg(&n);
   362  	dneg = d.hi >> 31;
   363  	if(dneg)
   364  		vneg(&d);
   365  	dodiv(n, d, 0, r);
   366  	if(nneg)
   367  		vneg(r);
   368  }
   369  
   370  void
   371  runtime·int64mod(Vlong n, Vlong d, Vlong q)
   372  {
   373  	_modv(&q, n, d);
   374  }
   375  
   376  void
   377  _rshav(Vlong *r, Vlong a, int b)
   378  {
   379  	long t;
   380  
   381  	t = a.hi;
   382  	if(b >= 32) {
   383  		r->hi = t>>31;
   384  		if(b >= 64) {
   385  			/* this is illegal re C standard */
   386  			r->lo = t>>31;
   387  			return;
   388  		}
   389  		r->lo = t >> (b-32);
   390  		return;
   391  	}
   392  	if(b <= 0) {
   393  		r->hi = t;
   394  		r->lo = a.lo;
   395  		return;
   396  	}
   397  	r->hi = t >> b;
   398  	r->lo = (t << (32-b)) | (a.lo >> b);
   399  }
   400  
   401  void
   402  _rshlv(Vlong *r, Vlong a, int b)
   403  {
   404  	ulong t;
   405  
   406  	t = a.hi;
   407  	if(b >= 32) {
   408  		r->hi = 0;
   409  		if(b >= 64) {
   410  			/* this is illegal re C standard */
   411  			r->lo = 0;
   412  			return;
   413  		}
   414  		r->lo = t >> (b-32);
   415  		return;
   416  	}
   417  	if(b <= 0) {
   418  		r->hi = t;
   419  		r->lo = a.lo;
   420  		return;
   421  	}
   422  	r->hi = t >> b;
   423  	r->lo = (t << (32-b)) | (a.lo >> b);
   424  }
   425  
   426  void
   427  _lshv(Vlong *r, Vlong a, int b)
   428  {
   429  	ulong t;
   430  
   431  	t = a.lo;
   432  	if(b >= 32) {
   433  		r->lo = 0;
   434  		if(b >= 64) {
   435  			/* this is illegal re C standard */
   436  			r->hi = 0;
   437  			return;
   438  		}
   439  		r->hi = t << (b-32);
   440  		return;
   441  	}
   442  	if(b <= 0) {
   443  		r->lo = t;
   444  		r->hi = a.hi;
   445  		return;
   446  	}
   447  	r->lo = t << b;
   448  	r->hi = (t >> (32-b)) | (a.hi << b);
   449  }
   450  
   451  void
   452  _andv(Vlong *r, Vlong a, Vlong b)
   453  {
   454  	r->hi = a.hi & b.hi;
   455  	r->lo = a.lo & b.lo;
   456  }
   457  
   458  void
   459  _orv(Vlong *r, Vlong a, Vlong b)
   460  {
   461  	r->hi = a.hi | b.hi;
   462  	r->lo = a.lo | b.lo;
   463  }
   464  
   465  void
   466  _xorv(Vlong *r, Vlong a, Vlong b)
   467  {
   468  	r->hi = a.hi ^ b.hi;
   469  	r->lo = a.lo ^ b.lo;
   470  }
   471  
   472  void
   473  _vpp(Vlong *l, Vlong *r)
   474  {
   475  
   476  	l->hi = r->hi;
   477  	l->lo = r->lo;
   478  	r->lo++;
   479  	if(r->lo == 0)
   480  		r->hi++;
   481  }
   482  
   483  void
   484  _vmm(Vlong *l, Vlong *r)
   485  {
   486  
   487  	l->hi = r->hi;
   488  	l->lo = r->lo;
   489  	if(r->lo == 0)
   490  		r->hi--;
   491  	r->lo--;
   492  }
   493  
   494  void
   495  _ppv(Vlong *l, Vlong *r)
   496  {
   497  
   498  	r->lo++;
   499  	if(r->lo == 0)
   500  		r->hi++;
   501  	l->hi = r->hi;
   502  	l->lo = r->lo;
   503  }
   504  
   505  void
   506  _mmv(Vlong *l, Vlong *r)
   507  {
   508  
   509  	if(r->lo == 0)
   510  		r->hi--;
   511  	r->lo--;
   512  	l->hi = r->hi;
   513  	l->lo = r->lo;
   514  }
   515  
   516  void
   517  _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
   518  {
   519  	Vlong t, u;
   520  
   521  	u.lo = 0;
   522  	u.hi = 0;
   523  	switch(type) {
   524  	default:
   525  		runtime·abort();
   526  		break;
   527  
   528  	case 1:	/* schar */
   529  		t.lo = *(schar*)lv;
   530  		t.hi = t.lo >> 31;
   531  		fn(&u, t, rv);
   532  		*(schar*)lv = u.lo;
   533  		break;
   534  
   535  	case 2:	/* uchar */
   536  		t.lo = *(uchar*)lv;
   537  		t.hi = 0;
   538  		fn(&u, t, rv);
   539  		*(uchar*)lv = u.lo;
   540  		break;
   541  
   542  	case 3:	/* short */
   543  		t.lo = *(short*)lv;
   544  		t.hi = t.lo >> 31;
   545  		fn(&u, t, rv);
   546  		*(short*)lv = u.lo;
   547  		break;
   548  
   549  	case 4:	/* ushort */
   550  		t.lo = *(ushort*)lv;
   551  		t.hi = 0;
   552  		fn(&u, t, rv);
   553  		*(ushort*)lv = u.lo;
   554  		break;
   555  
   556  	case 9:	/* int */
   557  		t.lo = *(int*)lv;
   558  		t.hi = t.lo >> 31;
   559  		fn(&u, t, rv);
   560  		*(int*)lv = u.lo;
   561  		break;
   562  
   563  	case 10:	/* uint */
   564  		t.lo = *(uint*)lv;
   565  		t.hi = 0;
   566  		fn(&u, t, rv);
   567  		*(uint*)lv = u.lo;
   568  		break;
   569  
   570  	case 5:	/* long */
   571  		t.lo = *(long*)lv;
   572  		t.hi = t.lo >> 31;
   573  		fn(&u, t, rv);
   574  		*(long*)lv = u.lo;
   575  		break;
   576  
   577  	case 6:	/* ulong */
   578  		t.lo = *(ulong*)lv;
   579  		t.hi = 0;
   580  		fn(&u, t, rv);
   581  		*(ulong*)lv = u.lo;
   582  		break;
   583  
   584  	case 7:	/* vlong */
   585  	case 8:	/* uvlong */
   586  		fn(&u, *(Vlong*)lv, rv);
   587  		*(Vlong*)lv = u;
   588  		break;
   589  	}
   590  	*ret = u;
   591  }
   592  
   593  void
   594  _p2v(Vlong *ret, void *p)
   595  {
   596  	long t;
   597  
   598  	t = (ulong)p;
   599  	ret->lo = t;
   600  	ret->hi = 0;
   601  }
   602  
   603  void
   604  _sl2v(Vlong *ret, long sl)
   605  {
   606  	long t;
   607  
   608  	t = sl;
   609  	ret->lo = t;
   610  	ret->hi = t >> 31;
   611  }
   612  
   613  void
   614  _ul2v(Vlong *ret, ulong ul)
   615  {
   616  	long t;
   617  
   618  	t = ul;
   619  	ret->lo = t;
   620  	ret->hi = 0;
   621  }
   622  
   623  void
   624  _si2v(Vlong *ret, int si)
   625  {
   626  	long t;
   627  
   628  	t = si;
   629  	ret->lo = t;
   630  	ret->hi = t >> 31;
   631  }
   632  
   633  void
   634  _ui2v(Vlong *ret, uint ui)
   635  {
   636  	long t;
   637  
   638  	t = ui;
   639  	ret->lo = t;
   640  	ret->hi = 0;
   641  }
   642  
   643  void
   644  _sh2v(Vlong *ret, long sh)
   645  {
   646  	long t;
   647  
   648  	t = (sh << 16) >> 16;
   649  	ret->lo = t;
   650  	ret->hi = t >> 31;
   651  }
   652  
   653  void
   654  _uh2v(Vlong *ret, ulong ul)
   655  {
   656  	long t;
   657  
   658  	t = ul & 0xffff;
   659  	ret->lo = t;
   660  	ret->hi = 0;
   661  }
   662  
   663  void
   664  _sc2v(Vlong *ret, long uc)
   665  {
   666  	long t;
   667  
   668  	t = (uc << 24) >> 24;
   669  	ret->lo = t;
   670  	ret->hi = t >> 31;
   671  }
   672  
   673  void
   674  _uc2v(Vlong *ret, ulong ul)
   675  {
   676  	long t;
   677  
   678  	t = ul & 0xff;
   679  	ret->lo = t;
   680  	ret->hi = 0;
   681  }
   682  
   683  long
   684  _v2sc(Vlong rv)
   685  {
   686  	long t;
   687  
   688  	t = rv.lo & 0xff;
   689  	return (t << 24) >> 24;
   690  }
   691  
   692  long
   693  _v2uc(Vlong rv)
   694  {
   695  
   696  	return rv.lo & 0xff;
   697  }
   698  
   699  long
   700  _v2sh(Vlong rv)
   701  {
   702  	long t;
   703  
   704  	t = rv.lo & 0xffff;
   705  	return (t << 16) >> 16;
   706  }
   707  
   708  long
   709  _v2uh(Vlong rv)
   710  {
   711  
   712  	return rv.lo & 0xffff;
   713  }
   714  
   715  long
   716  _v2sl(Vlong rv)
   717  {
   718  
   719  	return rv.lo;
   720  }
   721  
   722  long
   723  _v2ul(Vlong rv)
   724  {
   725  
   726  	return rv.lo;
   727  }
   728  
   729  long
   730  _v2si(Vlong rv)
   731  {
   732  
   733  	return rv.lo;
   734  }
   735  
   736  long
   737  _v2ui(Vlong rv)
   738  {
   739  
   740  	return rv.lo;
   741  }
   742  
   743  int
   744  _testv(Vlong rv)
   745  {
   746  	return rv.lo || rv.hi;
   747  }
   748  
   749  int
   750  _eqv(Vlong lv, Vlong rv)
   751  {
   752  	return lv.lo == rv.lo && lv.hi == rv.hi;
   753  }
   754  
   755  int
   756  _nev(Vlong lv, Vlong rv)
   757  {
   758  	return lv.lo != rv.lo || lv.hi != rv.hi;
   759  }
   760  
   761  int
   762  _ltv(Vlong lv, Vlong rv)
   763  {
   764  	return (long)lv.hi < (long)rv.hi ||
   765  		(lv.hi == rv.hi && lv.lo < rv.lo);
   766  }
   767  
   768  int
   769  _lev(Vlong lv, Vlong rv)
   770  {
   771  	return (long)lv.hi < (long)rv.hi ||
   772  		(lv.hi == rv.hi && lv.lo <= rv.lo);
   773  }
   774  
   775  int
   776  _gtv(Vlong lv, Vlong rv)
   777  {
   778  	return (long)lv.hi > (long)rv.hi ||
   779  		(lv.hi == rv.hi && lv.lo > rv.lo);
   780  }
   781  
   782  int
   783  _gev(Vlong lv, Vlong rv)
   784  {
   785  	return (long)lv.hi > (long)rv.hi ||
   786  		(lv.hi == rv.hi && lv.lo >= rv.lo);
   787  }
   788  
   789  int
   790  _lov(Vlong lv, Vlong rv)
   791  {
   792  	return lv.hi < rv.hi ||
   793  		(lv.hi == rv.hi && lv.lo < rv.lo);
   794  }
   795  
   796  int
   797  _lsv(Vlong lv, Vlong rv)
   798  {
   799  	return lv.hi < rv.hi ||
   800  		(lv.hi == rv.hi && lv.lo <= rv.lo);
   801  }
   802  
   803  int
   804  _hiv(Vlong lv, Vlong rv)
   805  {
   806  	return lv.hi > rv.hi ||
   807  		(lv.hi == rv.hi && lv.lo > rv.lo);
   808  }
   809  
   810  int
   811  _hsv(Vlong lv, Vlong rv)
   812  {
   813  	return lv.hi > rv.hi ||
   814  		(lv.hi == rv.hi && lv.lo >= rv.lo);
   815  }