github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/8c/mul.c (about)

     1  // Inferno utils/8c/mul.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  #include "gc.h"
    32  
    33  typedef struct	Malg	Malg;
    34  typedef struct	Mparam	Mparam;
    35  
    36  struct	Malg
    37  {
    38  	schar	vals[10];
    39  };
    40  
    41  struct	Mparam
    42  {
    43  	uint32	value;
    44  	schar	alg;
    45  	char	neg;
    46  	char	shift;
    47  	char	arg;
    48  	schar	off;
    49  };
    50  
    51  static	Mparam	multab[32];
    52  static	int	mulptr;
    53  
    54  static	Malg	malgs[]	=
    55  {
    56  	{0, 100},
    57  	{-1, 1, 100},
    58  	{-9, -5, -3, 3, 5, 9, 100},
    59  	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
    60  	{-8, -4, -2, 2, 4, 8, 100},
    61  };
    62  
    63  /*
    64   * return position of lowest 1
    65   */
    66  int
    67  lowbit(uint32 v)
    68  {
    69  	int s, i;
    70  	uint32 m;
    71  
    72  	s = 0;
    73  	m = 0xFFFFFFFFUL;
    74  	for(i = 16; i > 0; i >>= 1) {
    75  		m >>= i;
    76  		if((v & m) == 0) {
    77  			v >>= i;
    78  			s += i;
    79  		}
    80  	}
    81  	return s;
    82  }
    83  
    84  void
    85  genmuladd(Node *d, Node *s, int m, Node *a)
    86  {
    87  	Node nod;
    88  
    89  	nod.op = OINDEX;
    90  	nod.left = a;
    91  	nod.right = s;
    92  	nod.scale = m;
    93  	nod.type = types[TIND];
    94  	nod.xoffset = 0;
    95  	xcom(&nod);
    96  	gopcode(OADDR, d->type, &nod, d);
    97  }
    98  
    99  void
   100  mulparam(uint32 m, Mparam *mp)
   101  {
   102  	int c, i, j, n, o, q, s;
   103  	int bc, bi, bn, bo, bq, bs, bt;
   104  	schar *p;
   105  	int32 u;
   106  	uint32 t;
   107  
   108  	bc = bq = 10;
   109  	bi = bn = bo = bs = bt = 0;
   110  	for(i = 0; i < nelem(malgs); i++) {
   111  		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
   112  		for(s = 0; s < 2; s++) {
   113  			c = 10;
   114  			q = 10;
   115  			u = m - o;
   116  			if(u == 0)
   117  				continue;
   118  			if(s) {
   119  				o = -o;
   120  				if(o > 0)
   121  					continue;
   122  				u = -u;
   123  			}
   124  			n = lowbit(u);
   125  			t = (uint32)u >> n;
   126  			switch(i) {
   127  			case 0:
   128  				if(t == 1) {
   129  					c = s + 1;
   130  					q = 0;
   131  					break;
   132  				}
   133  				switch(t) {
   134  				case 3:
   135  				case 5:
   136  				case 9:
   137  					c = s + 1;
   138  					if(n)
   139  						c++;
   140  					q = 0;
   141  					break;
   142  				}
   143  				if(s)
   144  					break;
   145  				switch(t) {
   146  				case 15:
   147  				case 25:
   148  				case 27:
   149  				case 45:
   150  				case 81:
   151  					c = 2;
   152  					if(n)
   153  						c++;
   154  					q = 1;
   155  					break;
   156  				}
   157  				break;
   158  			case 1:
   159  				if(t == 1) {
   160  					c = 3;
   161  					q = 3;
   162  					break;
   163  				}
   164  				switch(t) {
   165  				case 3:
   166  				case 5:
   167  				case 9:
   168  					c = 3;
   169  					q = 2;
   170  					break;
   171  				}
   172  				break;
   173  			case 2:
   174  				if(t == 1) {
   175  					c = 3;
   176  					q = 2;
   177  					break;
   178  				}
   179  				break;
   180  			case 3:
   181  				if(s)
   182  					break;
   183  				if(t == 1) {
   184  					c = 3;
   185  					q = 1;
   186  					break;
   187  				}
   188  				break;
   189  			case 4:
   190  				if(t == 1) {
   191  					c = 3;
   192  					q = 0;
   193  					break;
   194  				}
   195  				break;
   196  			}
   197  			if(c < bc || (c == bc && q > bq)) {
   198  				bc = c;
   199  				bi = i;
   200  				bn = n;
   201  				bo = o;
   202  				bq = q;
   203  				bs = s;
   204  				bt = t;
   205  			}
   206  		}
   207  	}
   208  	mp->value = m;
   209  	if(bc <= 3) {
   210  		mp->alg = bi;
   211  		mp->shift = bn;
   212  		mp->off = bo;
   213  		mp->neg = bs;
   214  		mp->arg = bt;
   215  	}
   216  	else
   217  		mp->alg = -1;
   218  }
   219  
   220  int
   221  m0(int a)
   222  {
   223  	switch(a) {
   224  	case -2:
   225  	case 2:
   226  		return 2;
   227  	case -3:
   228  	case 3:
   229  		return 2;
   230  	case -4:
   231  	case 4:
   232  		return 4;
   233  	case -5:
   234  	case 5:
   235  		return 4;
   236  	case 6:
   237  		return 2;
   238  	case -8:
   239  	case 8:
   240  		return 8;
   241  	case -9:
   242  	case 9:
   243  		return 8;
   244  	case 10:
   245  		return 4;
   246  	case 12:
   247  		return 2;
   248  	case 15:
   249  		return 2;
   250  	case 18:
   251  		return 8;
   252  	case 20:
   253  		return 4;
   254  	case 24:
   255  		return 2;
   256  	case 25:
   257  		return 4;
   258  	case 27:
   259  		return 2;
   260  	case 36:
   261  		return 8;
   262  	case 40:
   263  		return 4;
   264  	case 45:
   265  		return 4;
   266  	case 72:
   267  		return 8;
   268  	case 81:
   269  		return 8;
   270  	}
   271  	diag(Z, "bad m0");
   272  	return 0;
   273  }
   274  
   275  int
   276  m1(int a)
   277  {
   278  	switch(a) {
   279  	case 15:
   280  		return 4;
   281  	case 25:
   282  		return 4;
   283  	case 27:
   284  		return 8;
   285  	case 45:
   286  		return 8;
   287  	case 81:
   288  		return 8;
   289  	}
   290  	diag(Z, "bad m1");
   291  	return 0;
   292  }
   293  
   294  int
   295  m2(int a)
   296  {
   297  	switch(a) {
   298  	case 6:
   299  		return 2;
   300  	case 10:
   301  		return 2;
   302  	case 12:
   303  		return 4;
   304  	case 18:
   305  		return 2;
   306  	case 20:
   307  		return 4;
   308  	case 24:
   309  		return 8;
   310  	case 36:
   311  		return 4;
   312  	case 40:
   313  		return 8;
   314  	case 72:
   315  		return 8;
   316  	}
   317  	diag(Z, "bad m2");
   318  	return 0;
   319  }
   320  
   321  void
   322  shiftit(Type *t, Node *s, Node *d)
   323  {
   324  	int32 c;
   325  
   326  	c = (int32)s->vconst & 31;
   327  	switch(c) {
   328  	case 0:
   329  		break;
   330  	case 1:
   331  		gopcode(OADD, t, d, d);
   332  		break;
   333  	default:
   334  		gopcode(OASHL, t, s, d);
   335  	}
   336  }
   337  
   338  static int
   339  mulgen1(uint32 v, Node *n)
   340  {
   341  	int i, o;
   342  	Mparam *p;
   343  	Node nod, nods;
   344  
   345  	for(i = 0; i < nelem(multab); i++) {
   346  		p = &multab[i];
   347  		if(p->value == v)
   348  			goto found;
   349  	}
   350  
   351  	p = &multab[mulptr];
   352  	if(++mulptr == nelem(multab))
   353  		mulptr = 0;
   354  
   355  	mulparam(v, p);
   356  
   357  found:
   358  //	print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
   359  	if(p->alg < 0)
   360  		return 0;
   361  
   362  	nods = *nodconst(p->shift);
   363  
   364  	o = OADD;
   365  	if(p->alg > 0) {
   366  		regalloc(&nod, n, Z);
   367  		if(p->off < 0)
   368  			o = OSUB;
   369  	}
   370  
   371  	switch(p->alg) {
   372  	case 0:
   373  		switch(p->arg) {
   374  		case 1:
   375  			shiftit(n->type, &nods, n);
   376  			break;
   377  		case 15:
   378  		case 25:
   379  		case 27:
   380  		case 45:
   381  		case 81:
   382  			genmuladd(n, n, m1(p->arg), n);
   383  			/* fall thru */
   384  		case 3:
   385  		case 5:
   386  		case 9:
   387  			genmuladd(n, n, m0(p->arg), n);
   388  			shiftit(n->type, &nods, n);
   389  			break;
   390  		default:
   391  			goto bad;
   392  		}
   393  		if(p->neg == 1)
   394  			gins(ANEGL, Z, n);
   395  		break;
   396  	case 1:
   397  		switch(p->arg) {
   398  		case 1:
   399  			gmove(n, &nod);
   400  			shiftit(n->type, &nods, &nod);
   401  			break;
   402  		case 3:
   403  		case 5:
   404  		case 9:
   405  			genmuladd(&nod, n, m0(p->arg), n);
   406  			shiftit(n->type, &nods, &nod);
   407  			break;
   408  		default:
   409  			goto bad;
   410  		}
   411  		if(p->neg)
   412  			gopcode(o, n->type, &nod, n);
   413  		else {
   414  			gopcode(o, n->type, n, &nod);
   415  			gmove(&nod, n);
   416  		}
   417  		break;
   418  	case 2:
   419  		genmuladd(&nod, n, m0(p->off), n);
   420  		shiftit(n->type, &nods, n);
   421  		goto comop;
   422  	case 3:
   423  		genmuladd(&nod, n, m0(p->off), n);
   424  		shiftit(n->type, &nods, n);
   425  		genmuladd(n, &nod, m2(p->off), n);
   426  		break;
   427  	case 4:
   428  		genmuladd(&nod, n, m0(p->off), nodconst(0));
   429  		shiftit(n->type, &nods, n);
   430  		goto comop;
   431  	default:
   432  		diag(Z, "bad mul alg");
   433  		break;
   434  	comop:
   435  		if(p->neg) {
   436  			gopcode(o, n->type, n, &nod);
   437  			gmove(&nod, n);
   438  		}
   439  		else
   440  			gopcode(o, n->type, &nod, n);
   441  	}
   442  
   443  	if(p->alg > 0)
   444  		regfree(&nod);
   445  
   446  	return 1;
   447  
   448  bad:
   449  	diag(Z, "mulgen botch");
   450  	return 1;
   451  }
   452  
   453  void
   454  mulgen(Type *t, Node *r, Node *n)
   455  {
   456  	if(!mulgen1(r->vconst, n))
   457  		gopcode(OMUL, t, r, n);
   458  }