| // Inferno utils/6c/mul.c | |
| // http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c | |
| // | |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. | |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) | |
| // Portions Copyright © 1997-1999 Vita Nuova Limited | |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) | |
| // Portions Copyright © 2004,2006 Bruce Ellis | |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) | |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others | |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. | |
| // | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy | |
| // of this software and associated documentation files (the "Software"), to deal | |
| // in the Software without restriction, including without limitation the rights | |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| // copies of the Software, and to permit persons to whom the Software is | |
| // furnished to do so, subject to the following conditions: | |
| // | |
| // The above copyright notice and this permission notice shall be included in | |
| // all copies or substantial portions of the Software. | |
| // | |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| // THE SOFTWARE. | |
| #include "gc.h" | |
| typedef struct Malg Malg; | |
| typedef struct Mparam Mparam; | |
| struct Malg | |
| { | |
| char vals[10]; | |
| }; | |
| struct Mparam | |
| { | |
| uint32 value; | |
| char alg; | |
| char neg; | |
| char shift; | |
| char arg; | |
| char off; | |
| }; | |
| static Mparam multab[32]; | |
| static int mulptr; | |
| static Malg malgs[] = | |
| { | |
| {0, 100}, | |
| {-1, 1, 100}, | |
| {-9, -5, -3, 3, 5, 9, 100}, | |
| {6, 10, 12, 18, 20, 24, 36, 40, 72, 100}, | |
| {-8, -4, -2, 2, 4, 8, 100}, | |
| }; | |
| /* | |
| * return position of lowest 1 | |
| */ | |
| int | |
| lowbit(uint32 v) | |
| { | |
| int s, i; | |
| uint32 m; | |
| s = 0; | |
| m = 0xFFFFFFFFUL; | |
| for(i = 16; i > 0; i >>= 1) { | |
| m >>= i; | |
| if((v & m) == 0) { | |
| v >>= i; | |
| s += i; | |
| } | |
| } | |
| return s; | |
| } | |
| void | |
| genmuladd(Node *d, Node *s, int m, Node *a) | |
| { | |
| Node nod; | |
| nod.op = OINDEX; | |
| nod.left = a; | |
| nod.right = s; | |
| nod.scale = m; | |
| nod.type = types[TIND]; | |
| nod.xoffset = 0; | |
| xcom(&nod); | |
| gopcode(OADDR, d->type, &nod, d); | |
| } | |
| void | |
| mulparam(uint32 m, Mparam *mp) | |
| { | |
| int c, i, j, n, o, q, s; | |
| int bc, bi, bn, bo, bq, bs, bt; | |
| char *p; | |
| int32 u; | |
| uint32 t; | |
| bc = bq = 10; | |
| bi = bn = bo = bs = bt = 0; | |
| for(i = 0; i < nelem(malgs); i++) { | |
| for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++) | |
| for(s = 0; s < 2; s++) { | |
| c = 10; | |
| q = 10; | |
| u = m - o; | |
| if(u == 0) | |
| continue; | |
| if(s) { | |
| o = -o; | |
| if(o > 0) | |
| continue; | |
| u = -u; | |
| } | |
| n = lowbit(u); | |
| t = (uint32)u >> n; | |
| switch(i) { | |
| case 0: | |
| if(t == 1) { | |
| c = s + 1; | |
| q = 0; | |
| break; | |
| } | |
| switch(t) { | |
| case 3: | |
| case 5: | |
| case 9: | |
| c = s + 1; | |
| if(n) | |
| c++; | |
| q = 0; | |
| break; | |
| } | |
| if(s) | |
| break; | |
| switch(t) { | |
| case 15: | |
| case 25: | |
| case 27: | |
| case 45: | |
| case 81: | |
| c = 2; | |
| if(n) | |
| c++; | |
| q = 1; | |
| break; | |
| } | |
| break; | |
| case 1: | |
| if(t == 1) { | |
| c = 3; | |
| q = 3; | |
| break; | |
| } | |
| switch(t) { | |
| case 3: | |
| case 5: | |
| case 9: | |
| c = 3; | |
| q = 2; | |
| break; | |
| } | |
| break; | |
| case 2: | |
| if(t == 1) { | |
| c = 3; | |
| q = 2; | |
| break; | |
| } | |
| break; | |
| case 3: | |
| if(s) | |
| break; | |
| if(t == 1) { | |
| c = 3; | |
| q = 1; | |
| break; | |
| } | |
| break; | |
| case 4: | |
| if(t == 1) { | |
| c = 3; | |
| q = 0; | |
| break; | |
| } | |
| break; | |
| } | |
| if(c < bc || (c == bc && q > bq)) { | |
| bc = c; | |
| bi = i; | |
| bn = n; | |
| bo = o; | |
| bq = q; | |
| bs = s; | |
| bt = t; | |
| } | |
| } | |
| } | |
| mp->value = m; | |
| if(bc <= 3) { | |
| mp->alg = bi; | |
| mp->shift = bn; | |
| mp->off = bo; | |
| mp->neg = bs; | |
| mp->arg = bt; | |
| } | |
| else | |
| mp->alg = -1; | |
| } | |
| int | |
| m0(int a) | |
| { | |
| switch(a) { | |
| case -2: | |
| case 2: | |
| return 2; | |
| case -3: | |
| case 3: | |
| return 2; | |
| case -4: | |
| case 4: | |
| return 4; | |
| case -5: | |
| case 5: | |
| return 4; | |
| case 6: | |
| return 2; | |
| case -8: | |
| case 8: | |
| return 8; | |
| case -9: | |
| case 9: | |
| return 8; | |
| case 10: | |
| return 4; | |
| case 12: | |
| return 2; | |
| case 15: | |
| return 2; | |
| case 18: | |
| return 8; | |
| case 20: | |
| return 4; | |
| case 24: | |
| return 2; | |
| case 25: | |
| return 4; | |
| case 27: | |
| return 2; | |
| case 36: | |
| return 8; | |
| case 40: | |
| return 4; | |
| case 45: | |
| return 4; | |
| case 72: | |
| return 8; | |
| case 81: | |
| return 8; | |
| } | |
| diag(Z, "bad m0"); | |
| return 0; | |
| } | |
| int | |
| m1(int a) | |
| { | |
| switch(a) { | |
| case 15: | |
| return 4; | |
| case 25: | |
| return 4; | |
| case 27: | |
| return 8; | |
| case 45: | |
| return 8; | |
| case 81: | |
| return 8; | |
| } | |
| diag(Z, "bad m1"); | |
| return 0; | |
| } | |
| int | |
| m2(int a) | |
| { | |
| switch(a) { | |
| case 6: | |
| return 2; | |
| case 10: | |
| return 2; | |
| case 12: | |
| return 4; | |
| case 18: | |
| return 2; | |
| case 20: | |
| return 4; | |
| case 24: | |
| return 8; | |
| case 36: | |
| return 4; | |
| case 40: | |
| return 8; | |
| case 72: | |
| return 8; | |
| } | |
| diag(Z, "bad m2"); | |
| return 0; | |
| } | |
| void | |
| shiftit(Type *t, Node *s, Node *d) | |
| { | |
| int32 c; | |
| c = (int32)s->vconst & 31; | |
| switch(c) { | |
| case 0: | |
| break; | |
| case 1: | |
| gopcode(OADD, t, d, d); | |
| break; | |
| default: | |
| gopcode(OASHL, t, s, d); | |
| } | |
| } | |
| static int | |
| mulgen1(uint32 v, Node *n) | |
| { | |
| int i, o; | |
| Mparam *p; | |
| Node nod, nods; | |
| for(i = 0; i < nelem(multab); i++) { | |
| p = &multab[i]; | |
| if(p->value == v) | |
| goto found; | |
| } | |
| p = &multab[mulptr]; | |
| if(++mulptr == nelem(multab)) | |
| mulptr = 0; | |
| mulparam(v, p); | |
| found: | |
| // 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); | |
| if(p->alg < 0) | |
| return 0; | |
| nods = *nodconst(p->shift); | |
| o = OADD; | |
| if(p->alg > 0) { | |
| regalloc(&nod, n, Z); | |
| if(p->off < 0) | |
| o = OSUB; | |
| } | |
| switch(p->alg) { | |
| case 0: | |
| switch(p->arg) { | |
| case 1: | |
| shiftit(n->type, &nods, n); | |
| break; | |
| case 15: | |
| case 25: | |
| case 27: | |
| case 45: | |
| case 81: | |
| genmuladd(n, n, m1(p->arg), n); | |
| /* fall thru */ | |
| case 3: | |
| case 5: | |
| case 9: | |
| genmuladd(n, n, m0(p->arg), n); | |
| shiftit(n->type, &nods, n); | |
| break; | |
| default: | |
| goto bad; | |
| } | |
| if(p->neg == 1) | |
| gins(ANEGL, Z, n); | |
| break; | |
| case 1: | |
| switch(p->arg) { | |
| case 1: | |
| gmove(n, &nod); | |
| shiftit(n->type, &nods, &nod); | |
| break; | |
| case 3: | |
| case 5: | |
| case 9: | |
| genmuladd(&nod, n, m0(p->arg), n); | |
| shiftit(n->type, &nods, &nod); | |
| break; | |
| default: | |
| goto bad; | |
| } | |
| if(p->neg) | |
| gopcode(o, n->type, &nod, n); | |
| else { | |
| gopcode(o, n->type, n, &nod); | |
| gmove(&nod, n); | |
| } | |
| break; | |
| case 2: | |
| genmuladd(&nod, n, m0(p->off), n); | |
| shiftit(n->type, &nods, n); | |
| goto comop; | |
| case 3: | |
| genmuladd(&nod, n, m0(p->off), n); | |
| shiftit(n->type, &nods, n); | |
| genmuladd(n, &nod, m2(p->off), n); | |
| break; | |
| case 4: | |
| genmuladd(&nod, n, m0(p->off), nodconst(0)); | |
| shiftit(n->type, &nods, n); | |
| goto comop; | |
| default: | |
| diag(Z, "bad mul alg"); | |
| break; | |
| comop: | |
| if(p->neg) { | |
| gopcode(o, n->type, n, &nod); | |
| gmove(&nod, n); | |
| } | |
| else | |
| gopcode(o, n->type, &nod, n); | |
| } | |
| if(p->alg > 0) | |
| regfree(&nod); | |
| return 1; | |
| bad: | |
| diag(Z, "mulgen botch"); | |
| return 1; | |
| } | |
| void | |
| mulgen(Type *t, Node *r, Node *n) | |
| { | |
| if(!mulgen1(r->vconst, n)) | |
| gopcode(OMUL, t, r, n); | |
| } |