diff options
Diffstat (limited to 'src/cmd/cc/scon.c')
-rw-r--r-- | src/cmd/cc/scon.c | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c new file mode 100644 index 000000000..193331f77 --- /dev/null +++ b/src/cmd/cc/scon.c @@ -0,0 +1,637 @@ +// Inferno utils/cc/scon.c +// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.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 <u.h> +#include "cc.h" + +static Node* +acast(Type *t, Node *n) +{ + if(n->type->etype != t->etype || n->op == OBIT) { + n = new1(OCAST, n, Z); + if(nocast(n->left->type, t)) + *n = *n->left; + n->type = t; + } + return n; +} + + +void +evconst(Node *n) +{ + Node *l, *r; + int et, isf; + vlong v; + double d; + + if(n == Z || n->type == T) + return; + + et = n->type->etype; + isf = typefd[et]; + + l = n->left; + r = n->right; + + d = 0; + v = 0; + + switch(n->op) { + default: + return; + + case ONEG: + if(isf) + d = -l->fconst; + else + v = -l->vconst; + break; + + case OCOM: + v = ~l->vconst; + break; + + case OCAST: + if(et == TVOID) + return; + et = l->type->etype; + if(isf) { + if(typefd[et]) + d = l->fconst; + else + d = l->vconst; + } else { + if(typefd[et]) + v = l->fconst; + else + v = convvtox(l->vconst, n->type->etype); + } + break; + + case OCONST: + break; + + case OADD: + if(isf) + d = l->fconst + r->fconst; + else { + v = l->vconst + r->vconst; + } + break; + + case OSUB: + if(isf) + d = l->fconst - r->fconst; + else + v = l->vconst - r->vconst; + break; + + case OMUL: + if(isf) + d = l->fconst * r->fconst; + else { + v = l->vconst * r->vconst; + } + break; + + case OLMUL: + v = (uvlong)l->vconst * (uvlong)r->vconst; + break; + + + case ODIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + if(isf) + d = l->fconst / r->fconst; + else + v = l->vconst / r->vconst; + break; + + case OLDIV: + if(vconst(r) == 0) { + warn(n, "divide by zero"); + return; + } + v = (uvlong)l->vconst / (uvlong)r->vconst; + break; + + case OMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = l->vconst % r->vconst; + break; + + case OLMOD: + if(vconst(r) == 0) { + warn(n, "modulo by zero"); + return; + } + v = (uvlong)l->vconst % (uvlong)r->vconst; + break; + + case OAND: + v = l->vconst & r->vconst; + break; + + case OOR: + v = l->vconst | r->vconst; + break; + + case OXOR: + v = l->vconst ^ r->vconst; + break; + + case OLSHR: + v = (uvlong)l->vconst >> r->vconst; + break; + + case OASHR: + v = l->vconst >> r->vconst; + break; + + case OASHL: + v = l->vconst << r->vconst; + break; + + case OLO: + v = (uvlong)l->vconst < (uvlong)r->vconst; + break; + + case OLT: + if(typefd[l->type->etype]) + v = l->fconst < r->fconst; + else + v = l->vconst < r->vconst; + break; + + case OHI: + v = (uvlong)l->vconst > (uvlong)r->vconst; + break; + + case OGT: + if(typefd[l->type->etype]) + v = l->fconst > r->fconst; + else + v = l->vconst > r->vconst; + break; + + case OLS: + v = (uvlong)l->vconst <= (uvlong)r->vconst; + break; + + case OLE: + if(typefd[l->type->etype]) + v = l->fconst <= r->fconst; + else + v = l->vconst <= r->vconst; + break; + + case OHS: + v = (uvlong)l->vconst >= (uvlong)r->vconst; + break; + + case OGE: + if(typefd[l->type->etype]) + v = l->fconst >= r->fconst; + else + v = l->vconst >= r->vconst; + break; + + case OEQ: + if(typefd[l->type->etype]) + v = l->fconst == r->fconst; + else + v = l->vconst == r->vconst; + break; + + case ONE: + if(typefd[l->type->etype]) + v = l->fconst != r->fconst; + else + v = l->vconst != r->vconst; + break; + + case ONOT: + if(typefd[l->type->etype]) + v = !l->fconst; + else + v = !l->vconst; + break; + + case OANDAND: + if(typefd[l->type->etype]) + v = l->fconst && r->fconst; + else + v = l->vconst && r->vconst; + break; + + case OOROR: + if(typefd[l->type->etype]) + v = l->fconst || r->fconst; + else + v = l->vconst || r->vconst; + break; + } + if(isf) { + n->fconst = d; + } else { + n->vconst = convvtox(v, n->type->etype); + } + n->oldop = n->op; + n->op = OCONST; +} + +void +acom(Node *n) +{ + Type *t; + Node *l, *r; + int i; + + switch(n->op) + { + + case ONAME: + case OCONST: + case OSTRING: + case OINDREG: + case OREGISTER: + return; + + case ONEG: + l = n->left; + if(addo(n) && addo(l)) + break; + acom(l); + return; + + case OADD: + case OSUB: + case OMUL: + l = n->left; + r = n->right; + if(addo(n)) { + if(addo(r)) + break; + if(addo(l)) + break; + } + acom(l); + acom(r); + return; + + default: + l = n->left; + r = n->right; + if(l != Z) + acom(l); + if(r != Z) + acom(r); + return; + } + + /* bust terms out */ + t = n->type; + term[0].mult = 0; + term[0].node = Z; + nterm = 1; + acom1(1, n); + if(debug['m']) + for(i=0; i<nterm; i++) { + print("%d %3lld ", i, term[i].mult); + prtree1(term[i].node, 1, 0); + } + if(nterm < NTERM) + acom2(n, t); + n->type = t; +} + +int +acomcmp1(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + if(c1 < 0) + c1 = -c1; + c2 = t2->mult; + if(c2 < 0) + c2 = -c2; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + c1 = 1; + if(t1->mult < 0) + c1 = 0; + c2 = 1; + if(t2->mult < 0) + c2 = 0; + if(c2 -= c1) + return c2; + if(t2 > t1) + return 1; + return -1; +} + +int +acomcmp2(const void *a1, const void *a2) +{ + vlong c1, c2; + Term *t1, *t2; + + t1 = (Term*)a1; + t2 = (Term*)a2; + c1 = t1->mult; + c2 = t2->mult; + if(c1 > c2) + return 1; + if(c1 < c2) + return -1; + if(t2 > t1) + return 1; + return -1; +} + +void +acom2(Node *n, Type *t) +{ + Node *l, *r; + Term trm[NTERM]; + int et, nt, i, j; + vlong c1, c2; + + /* + * copy into automatic + */ + c2 = 0; + nt = nterm; + for(i=0; i<nt; i++) + trm[i] = term[i]; + /* + * recur on subtrees + */ + j = 0; + for(i=1; i<nt; i++) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + l = trm[i].node; + if(l != Z) { + j = 1; + acom(l); + } + } + c1 = trm[0].mult; + if(j == 0) { + n->oldop = n->op; + n->op = OCONST; + n->vconst = c1; + return; + } + et = t->etype; + + /* + * prepare constant term, + * combine it with an addressing term + */ + if(c1 != 0) { + l = new1(OCONST, Z, Z); + l->type = t; + l->vconst = c1; + trm[0].mult = 1; + for(i=1; i<nt; i++) { + if(trm[i].mult != 1) + continue; + r = trm[i].node; + if(r->op != OADDR) + continue; + r->type = t; + l = new1(OADD, r, l); + l->type = t; + trm[i].mult = 0; + break; + } + trm[0].node = l; + } + /* + * look for factorable terms + * c1*i + c1*c2*j -> c1*(i + c2*j) + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1); + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 < 0) + c1 = -c1; + if(c1 <= 1) + continue; + for(j=i+1; j<nt; j++) { + c2 = trm[j].mult; + if(c2 < 0) + c2 = -c2; + if(c2 <= 1) + continue; + if(c2 % c1) + continue; + r = trm[j].node; + if(r->type->etype != et) + r = acast(t, r); + c2 = trm[j].mult/trm[i].mult; + if(c2 != 1 && c2 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + r->right->vconst = c2; + } + l = trm[i].node; + if(l->type->etype != et) + l = acast(t, l); + r = new1(OADD, l, r); + r->type = t; + if(c2 == -1) + r->op = OSUB; + trm[i].node = r; + trm[j].mult = 0; + } + } + if(debug['m']) { + print("\n"); + for(i=0; i<nt; i++) { + print("%d %3lld ", i, trm[i].mult); + prtree1(trm[i].node, 1, 0); + } + } + + /* + * put it all back together + */ + qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2); + l = Z; + for(i=nt-1; i>=0; i--) { + c1 = trm[i].mult; + if(c1 == 0) + continue; + r = trm[i].node; + if(r->type->etype != et || r->op == OBIT) + r = acast(t, r); + if(c1 != 1 && c1 != -1) { + r = new1(OMUL, r, new(OCONST, Z, Z)); + r->type = t; + r->right->type = t; + if(c1 < 0) { + r->right->vconst = -c1; + c1 = -1; + } else { + r->right->vconst = c1; + c1 = 1; + } + } + if(l == Z) { + l = r; + c2 = c1; + continue; + } + if(c1 < 0) + if(c2 < 0) + l = new1(OADD, l, r); + else + l = new1(OSUB, l, r); + else + if(c2 < 0) { + l = new1(OSUB, r, l); + c2 = 1; + } else + l = new1(OADD, l, r); + l->type = t; + } + if(c2 < 0) { + r = new1(OCONST, 0, 0); + r->vconst = 0; + r->type = t; + l = new1(OSUB, r, l); + l->type = t; + } + *n = *l; +} + +void +acom1(vlong v, Node *n) +{ + Node *l, *r; + + if(v == 0 || nterm >= NTERM) + return; + if(!addo(n)) { + if(n->op == OCONST) + if(!typefd[n->type->etype]) { + term[0].mult += v*n->vconst; + return; + } + term[nterm].mult = v; + term[nterm].node = n; + nterm++; + return; + } + switch(n->op) { + + case OCAST: + acom1(v, n->left); + break; + + case ONEG: + acom1(-v, n->left); + break; + + case OADD: + acom1(v, n->left); + acom1(v, n->right); + break; + + case OSUB: + acom1(v, n->left); + acom1(-v, n->right); + break; + + case OMUL: + l = n->left; + r = n->right; + if(l->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*l->vconst, r); + break; + } + if(r->op == OCONST) + if(!typefd[n->type->etype]) { + acom1(v*r->vconst, l); + break; + } + break; + + default: + diag(n, "not addo"); + } +} + +int +addo(Node *n) +{ + + if(n != Z) + if(!typefd[n->type->etype]) + if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND]) + switch(n->op) { + + case OCAST: + if(nilcast(n->left->type, n->type)) + return 1; + break; + + case ONEG: + case OADD: + case OSUB: + return 1; + + case OMUL: + if(n->left->op == OCONST) + return 1; + if(n->right->op == OCONST) + return 1; + } + return 0; +} |