summaryrefslogtreecommitdiff
path: root/src/cmd/cc/sub.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cc/sub.c')
-rw-r--r--src/cmd/cc/sub.c2056
1 files changed, 2056 insertions, 0 deletions
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
new file mode 100644
index 000000000..e5992e213
--- /dev/null
+++ b/src/cmd/cc/sub.c
@@ -0,0 +1,2056 @@
+// Inferno utils/cc/sub.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.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"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+ Node *n;
+
+ n = alloc(sizeof(*n));
+ n->op = t;
+ n->left = l;
+ n->right = r;
+ if(l && t != OGOTO)
+ n->lineno = l->lineno;
+ else if(r)
+ n->lineno = r->lineno;
+ else
+ n->lineno = lineno;
+ newflag = 1;
+ return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+ Node *n;
+
+ n = new(o, l, r);
+ n->lineno = nearln;
+ return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+ print(" == %s ==\n", s);
+ prtree1(n, 0, 0);
+ print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+ int i;
+
+ if(f)
+ for(i=0; i<d; i++)
+ print(" ");
+ if(n == Z) {
+ print("Z\n");
+ return;
+ }
+ if(n->op == OLIST) {
+ prtree1(n->left, d, 0);
+ prtree1(n->right, d, 1);
+ return;
+ }
+ d++;
+ print("%O", n->op);
+ i = 3;
+ switch(n->op)
+ {
+ case ONAME:
+ print(" \"%F\"", n);
+ print(" %d", n->xoffset);
+ i = 0;
+ break;
+
+ case OINDREG:
+ print(" %d(R%d)", n->xoffset, n->reg);
+ i = 0;
+ break;
+
+ case OREGISTER:
+ if(n->xoffset)
+ print(" %d+R%d", n->xoffset, n->reg);
+ else
+ print(" R%d", n->reg);
+ i = 0;
+ break;
+
+ case OSTRING:
+ print(" \"%s\"", n->cstring);
+ i = 0;
+ break;
+
+ case OLSTRING:
+ print(" \"%S\"", n->rstring);
+ i = 0;
+ break;
+
+ case ODOT:
+ case OELEM:
+ print(" \"%F\"", n);
+ break;
+
+ case OCONST:
+ if(typefd[n->type->etype])
+ print(" \"%.8e\"", n->fconst);
+ else
+ print(" \"%lld\"", n->vconst);
+ i = 0;
+ break;
+ }
+ if(n->addable != 0)
+ print(" <%d>", n->addable);
+ if(n->type != T)
+ print(" %T", n->type);
+ if(n->complex != 0)
+ print(" (%d)", n->complex);
+ print(" %L\n", n->lineno);
+ if(i & 2)
+ prtree1(n->left, d, 1);
+ if(i & 1)
+ prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+ Type *t;
+
+ t = alloc(sizeof(*t));
+ t->etype = et;
+ t->link = d;
+ t->down = T;
+ t->sym = S;
+ t->width = ewidth[et];
+ t->offset = 0;
+ t->shift = 0;
+ t->nbits = 0;
+ t->garb = 0;
+ return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+ Type *nt;
+
+ nt = typ(TXXX, T);
+ *nt = *t;
+ return nt;
+}
+
+Type*
+garbt(Type *t, int32 b)
+{
+ Type *t1;
+
+ if(b & BGARB) {
+ t1 = copytyp(t);
+ t1->garb = simpleg(b);
+ return t1;
+ }
+ return t;
+}
+
+int
+simpleg(int32 b)
+{
+
+ b &= BGARB;
+ switch(b) {
+ case BCONSTNT:
+ return GCONSTNT;
+ case BVOLATILE:
+ return GVOLATILE;
+ case BVOLATILE|BCONSTNT:
+ return GCONSTNT|GVOLATILE;
+ }
+ return GXXX;
+}
+
+int
+simplec(int32 b)
+{
+
+ b &= BCLASS;
+ switch(b) {
+ case 0:
+ case BREGISTER:
+ return CXXX;
+ case BAUTO:
+ case BAUTO|BREGISTER:
+ return CAUTO;
+ case BEXTERN:
+ return CEXTERN;
+ case BEXTERN|BREGISTER:
+ return CEXREG;
+ case BSTATIC:
+ return CSTATIC;
+ case BTYPEDEF:
+ return CTYPEDEF;
+ case BTYPESTR:
+ return CTYPESTR;
+ }
+ diag(Z, "illegal combination of classes %Q", b);
+ return CXXX;
+}
+
+Type*
+simplet(int32 b)
+{
+
+ b &= ~BCLASS & ~BGARB;
+ switch(b) {
+ case BCHAR:
+ case BCHAR|BSIGNED:
+ return types[TCHAR];
+
+ case BCHAR|BUNSIGNED:
+ return types[TUCHAR];
+
+ case BSHORT:
+ case BSHORT|BINT:
+ case BSHORT|BSIGNED:
+ case BSHORT|BINT|BSIGNED:
+ return types[TSHORT];
+
+ case BUNSIGNED|BSHORT:
+ case BUNSIGNED|BSHORT|BINT:
+ return types[TUSHORT];
+
+ case 0:
+ case BINT:
+ case BINT|BSIGNED:
+ case BSIGNED:
+ return types[TINT];
+
+ case BUNSIGNED:
+ case BUNSIGNED|BINT:
+ return types[TUINT];
+
+ case BLONG:
+ case BLONG|BINT:
+ case BLONG|BSIGNED:
+ case BLONG|BINT|BSIGNED:
+ return types[TLONG];
+
+ case BUNSIGNED|BLONG:
+ case BUNSIGNED|BLONG|BINT:
+ return types[TULONG];
+
+ case BVLONG|BLONG:
+ case BVLONG|BLONG|BINT:
+ case BVLONG|BLONG|BSIGNED:
+ case BVLONG|BLONG|BINT|BSIGNED:
+ return types[TVLONG];
+
+ case BVLONG|BLONG|BUNSIGNED:
+ case BVLONG|BLONG|BINT|BUNSIGNED:
+ return types[TUVLONG];
+
+ case BFLOAT:
+ return types[TFLOAT];
+
+ case BDOUBLE:
+ case BDOUBLE|BLONG:
+ case BFLOAT|BLONG:
+ return types[TDOUBLE];
+
+ case BVOID:
+ return types[TVOID];
+ }
+
+ diag(Z, "illegal combination of types %Q", b);
+ return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+ int i;
+ uint32 b;
+
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1L << i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ttab[i]) {
+ if(ttab == tasign)
+ if(b == BSTRUCT || b == BUNION)
+ if(!sametype(t1, t2))
+ return 1;
+ if(n->op != OCAST)
+ if(b == BIND && i == TIND)
+ if(!sametype(t1, t2))
+ return 1;
+ return 0;
+ }
+ return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+
+ if(stcompat(n, t1, t2, ttab)) {
+ if(t1 == T)
+ diag(n, "incompatible type: \"%T\" for op \"%O\"",
+ t2, n->op);
+ else
+ diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+ t1, t2, n->op);
+ return 1;
+ }
+ return 0;
+}
+
+void
+makedot(Node *n, Type *t, int32 o)
+{
+ Node *n1, *n2;
+
+ if(t->nbits) {
+ n1 = new(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OBIT;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = n1->left->addable;
+ n = n1;
+ }
+ n->addable = n->left->addable;
+ if(n->addable == 0) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ n1->type = types[TLONG];
+ n->right = n1;
+ n->type = t;
+ return;
+ }
+ n->left->type = t;
+ if(o == 0) {
+ *n = *n->left;
+ return;
+ }
+ n->type = t;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = o;
+ t = typ(TIND, t);
+ t->width = types[TIND]->width;
+ n1->type = t;
+
+ n2 = new1(OADDR, n->left, Z);
+ n2->type = t;
+
+ n1 = new1(OADD, n1, n2);
+ n1->type = t;
+
+ n->op = OIND;
+ n->left = n1;
+ n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, int32 *off)
+{
+ Type *t1, *xt, *rt;
+
+ xt = T;
+
+ /*
+ * look it up by name
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == s) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+
+ /*
+ * look it up by type
+ */
+ if(s->class == CTYPEDEF || s->class == CTYPESTR)
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype])
+ if(sametype(s->type, t1)) {
+ if(xt != T)
+ goto ambig;
+ xt = t1;
+ }
+ if(xt != T) {
+ *off = xt->offset;
+ return xt;
+ }
+
+ /*
+ * look it up in unnamed substructures
+ */
+ for(t1 = t; t1 != T; t1 = t1->down)
+ if(t1->sym == S && typesu[t1->etype]){
+ rt = dotsearch(s, t1->link, n, off);
+ if(rt != T) {
+ if(xt != T)
+ goto ambig;
+ xt = rt;
+ *off += t1->offset;
+ }
+ }
+ return xt;
+
+ambig:
+ diag(n, "ambiguous structure element: %s", s->name);
+ return xt;
+}
+
+int32
+dotoffset(Type *st, Type *lt, Node *n)
+{
+ Type *t;
+ Sym *g;
+ int32 o, o1;
+
+ o = -1;
+ /*
+ * first try matching at the top level
+ * for matching tag names
+ */
+ g = st->tag;
+ if(g != S)
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(g == t->tag) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * second try matching at the top level
+ * for similar types
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(sametype(st, t)) {
+ if(o >= 0)
+ goto ambig;
+ o = t->offset;
+ }
+ if(o >= 0)
+ return o;
+
+ /*
+ * last try matching sub-levels
+ */
+ for(t=lt->link; t!=T; t=t->down)
+ if(t->sym == S)
+ if(typesu[t->etype]) {
+ o1 = dotoffset(st, t, n);
+ if(o1 >= 0) {
+ if(o >= 0)
+ goto ambig;
+ o = o1 + t->offset;
+ }
+ }
+ return o;
+
+ambig:
+ diag(n, "ambiguous unnamed structure element");
+ return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+ if(n != Z) {
+ if(n->type->etype != TDOUBLE)
+ return 1;
+ switch(n->op) {
+ case OCONST:
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ case OADD: /* no need to get more exotic than this */
+ case OSUB:
+ case OMUL:
+ case ODIV:
+ if(!allfloat(n->right, flag))
+ break;
+ case OCAST:
+ if(!allfloat(n->left, flag))
+ break;
+ if(flag)
+ n->type = types[TFLOAT];
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+ Type *l, *r;
+
+ l = il;
+ r = ir;
+
+ if(l == T)
+ return;
+ if(l->garb & GCONSTNT) {
+ warn(n, "assignment to a constant type (%T)", il);
+ return;
+ }
+ if(r == T)
+ return;
+ for(;;) {
+ if(l->etype != TIND || r->etype != TIND)
+ break;
+ l = l->link;
+ r = r->link;
+ if(l == T || r == T)
+ break;
+ if(r->garb & GCONSTNT)
+ if(!(l->garb & GCONSTNT)) {
+ warn(n, "assignment of a constant pointer type (%T)", ir);
+ break;
+ }
+ }
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+ if(st->etype == TFLOAT && allfloat(l, 0))
+ allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+ Type *lt;
+ Node *n1, *n2;
+ int32 o;
+
+ lt = l->type;
+ if(lt == T)
+ return;
+ if(st->etype == TIND && vconst(l) == 0) {
+ l->type = st;
+ l->vconst = 0;
+ return;
+ }
+ typeext1(st, l);
+
+ /*
+ * extension of C
+ * if assign of struct containing unnamed sub-struct
+ * to type of sub-struct, insert the DOT.
+ * if assign of *struct containing unnamed substruct
+ * to type of *sub-struct, insert the add-offset
+ */
+ if(typesu[st->etype] && typesu[lt->etype]) {
+ o = dotoffset(st, lt, l);
+ if(o >= 0) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ l->op = ODOT;
+ l->left = n1;
+ l->right = Z;
+ makedot(l, st, o);
+ }
+ return;
+ }
+ if(st->etype == TIND && typesu[st->link->etype])
+ if(lt->etype == TIND && typesu[lt->link->etype]) {
+ o = dotoffset(st->link, lt->link, l);
+ if(o >= 0) {
+ l->type = st;
+ if(o == 0)
+ return;
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *l;
+ n2 = new1(OCONST, Z, Z);
+ n2->vconst = o;
+ n2->type = st;
+ l->op = OADD;
+ l->left = n1;
+ l->right = n2;
+ }
+ return;
+ }
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+ int i, b;
+
+ if(t1->nbits)
+ return 0;
+ i = 0;
+ if(t2 != T)
+ i = t2->etype;
+ b = 1<<i;
+ i = 0;
+ if(t1 != T)
+ i = t1->etype;
+ if(b & ncast[i])
+ return 1;
+ return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+ int et1, et2;
+
+ if(t1 == T)
+ return 0;
+ if(t1->nbits)
+ return 0;
+ if(t2 == T)
+ return 0;
+ et1 = t1->etype;
+ et2 = t2->etype;
+ if(et1 == et2)
+ return 1;
+ if(typefd[et1] && typefd[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ if(typechlp[et1] && typechlp[et2]) {
+ if(ewidth[et1] < ewidth[et2])
+ return 1;
+ return 0;
+ }
+ return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+ Type *t1, *t2;
+ int i, j, k;
+ Node *n1;
+ int32 w;
+
+ t1 = n->left->type;
+ if(n->right == Z)
+ t2 = t1;
+ else
+ t2 = n->right->type;
+ i = TXXX;
+ if(t1 != T)
+ i = t1->etype;
+ j = TXXX;
+ if(t2 != T)
+ j = t2->etype;
+ k = tab[i][j];
+ if(k == TIND) {
+ if(i == TIND)
+ n->type = t1;
+ else
+ if(j == TIND)
+ n->type = t2;
+ } else {
+ /* convert up to at least int */
+ if(f == 1)
+ while(k < TINT)
+ k += 2;
+ n->type = types[k];
+ }
+ if(n->op == OSUB)
+ if(i == TIND && j == TIND) {
+ w = n->right->type->link->width;
+ if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+ goto bad;
+ n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+ if(0 && ewidth[TIND] > ewidth[TLONG]){
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = types[TLONG];
+ }
+ if(w > 1) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = ODIV;
+ n->left = n1;
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = n1;
+ w = vlog(n1);
+ if(w >= 0) {
+ n->op = OASHR;
+ n1->vconst = w;
+ }
+ }
+ return;
+ }
+ if(!sametype(n->type, n->left->type)) {
+ n->left = new1(OCAST, n->left, Z);
+ n->left->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w > 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->left = new1(OMUL, n->left, n1);
+ n->left->type = n->type;
+ }
+ }
+ }
+ if(n->right != Z)
+ if(!sametype(n->type, n->right->type)) {
+ n->right = new1(OCAST, n->right, Z);
+ n->right->type = n->type;
+ if(n->type->etype == TIND) {
+ w = n->type->link->width;
+ if(w < 1) {
+ snap(n->type->link);
+ w = n->type->link->width;
+ if(w < 1)
+ goto bad;
+ }
+ if(w != 1) {
+ n1 = new1(OCONST, Z, Z);
+ n1->vconst = w;
+ n1->type = n->type;
+ n->right = new1(OMUL, n->right, n1);
+ n->right->type = n->type;
+ }
+ }
+ }
+ return;
+bad:
+ diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+ uint32 c3;
+ int o, s1, s2, c1, c2;
+
+ if(!typechlp[n->type->etype])
+ return;
+ switch(n->op) {
+ default:
+ return;
+ case OASHL:
+ s1 = 0;
+ break;
+ case OLSHR:
+ s1 = 1;
+ break;
+ case OASHR:
+ s1 = 2;
+ break;
+ }
+ if(n->right->op != OCONST)
+ return;
+ if(n->left->op != OAND)
+ return;
+ if(n->left->right->op != OCONST)
+ return;
+ switch(n->left->left->op) {
+ default:
+ return;
+ case OASHL:
+ s2 = 0;
+ break;
+ case OLSHR:
+ s2 = 1;
+ break;
+ case OASHR:
+ s2 = 2;
+ break;
+ }
+ if(n->left->left->right->op != OCONST)
+ return;
+
+ c1 = n->right->vconst;
+ c2 = n->left->left->right->vconst;
+ c3 = n->left->right->vconst;
+
+/*
+ if(debug['h'])
+ print("%.3o %d %d %d #%.ux\n",
+ (s1<<3)|s2, c1, c2, topbit(c3), c3);
+*/
+
+ o = n->op;
+ switch((s1<<3)|s2) {
+ case 000: /* (((e <<u c2) & c3) <<u c1) */
+ c3 >>= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ goto rewrite1;
+
+ case 002: /* (((e >>s c2) & c3) <<u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ case 001: /* (((e >>u c2) & c3) <<u c1) */
+ if(c1 > c2) {
+ c3 <<= c2;
+ c1 -= c2;
+ o = OASHL;
+ goto rewrite1;
+ }
+ c3 <<= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ c1 = c2-c1;
+ o = OLSHR;
+ goto rewrite2;
+
+ case 022: /* (((e >>s c2) & c3) >>s c1) */
+ if(c2 <= 0)
+ break;
+ case 012: /* (((e >>s c2) & c3) >>u c1) */
+ if(topbit(c3) >= (32-c2))
+ break;
+ goto s11;
+ case 021: /* (((e >>u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31 && c2 <= 0)
+ break;
+ goto s11;
+ case 011: /* (((e >>u c2) & c3) >>u c1) */
+ s11:
+ c3 <<= c2;
+ c1 += c2;
+ if(c1 >= 32)
+ break;
+ o = OLSHR;
+ goto rewrite1;
+
+ case 020: /* (((e <<u c2) & c3) >>s c1) */
+ if(topbit(c3) >= 31)
+ break;
+ case 010: /* (((e <<u c2) & c3) >>u c1) */
+ c3 >>= c1;
+ if(c1 == c2)
+ goto rewrite0;
+ if(c1 > c2) {
+ c1 -= c2;
+ goto rewrite2;
+ }
+ c1 = c2 - c1;
+ o = OASHL;
+ goto rewrite2;
+ }
+ return;
+
+rewrite0: /* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+ *n = *n->left;
+ n->left = n->left->left;
+ n->right->vconst = c3;
+ return;
+rewrite1: /* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+ n->left->left = n->left->left->left;
+ n->left->right->vconst = c3;
+ n->right->vconst = c1;
+ n->op = o;
+ return;
+rewrite2: /* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+ *n = *n->left;
+ n->right->vconst = c3;
+ n->left->right->vconst = c1;
+ n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+ if(n != Z)
+ switch(n->op) {
+ case OCAST:
+ case ONOT:
+ case OADDR:
+ case OIND:
+ n = n->left;
+ goto loop;
+
+ case OCOND:
+ if(side(n->left))
+ break;
+ n = n->right;
+
+ case OEQ:
+ case ONE:
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ case OADD:
+ case OSUB:
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ case OAND:
+ case OOR:
+ case OXOR:
+ case OMOD:
+ case OLMOD:
+ case OANDAND:
+ case OOROR:
+ case OCOMMA:
+ case ODOT:
+ if(side(n->left))
+ break;
+ n = n->right;
+ goto loop;
+
+ case OSIGN:
+ case OSIZE:
+ case OCONST:
+ case OSTRING:
+ case OLSTRING:
+ case ONAME:
+ return 0;
+ }
+ return 1;
+}
+
+int
+vconst(Node *n)
+{
+ int i;
+
+ if(n == Z)
+ goto no;
+ if(n->op != OCONST)
+ goto no;
+ if(n->type == T)
+ goto no;
+ switch(n->type->etype)
+ {
+ case TFLOAT:
+ case TDOUBLE:
+ i = 100;
+ if(n->fconst > i || n->fconst < -i)
+ goto no;
+ i = n->fconst;
+ if(i != n->fconst)
+ goto no;
+ return i;
+
+ case TVLONG:
+ case TUVLONG:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ case TINT:
+ case TUINT:
+ case TLONG:
+ case TULONG:
+ case TIND:
+ i = n->vconst;
+ if(i != n->vconst)
+ goto no;
+ return i;
+ }
+no:
+ return -159; /* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+xlog2(uvlong v)
+{
+ int s, i;
+ uvlong m;
+
+ s = 0;
+ m = MASK(8*sizeof(uvlong));
+ for(i=32; i; i>>=1) {
+ m >>= i;
+ if(!(v & m)) {
+ v >>= i;
+ s += i;
+ }
+ }
+ if(v == 1)
+ return s;
+ return -1;
+}
+
+int
+vlog(Node *n)
+{
+ if(n->op != OCONST)
+ goto bad;
+ if(typefd[n->type->etype])
+ goto bad;
+
+ return xlog2(n->vconst);
+
+bad:
+ return -1;
+}
+
+int
+topbit(uint32 v)
+{
+ int i;
+
+ for(i = -1; v; i++)
+ v >>= 1;
+ return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ * if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+ vlong v;
+
+ if(l->op != OCONST)
+ return;
+ if(r->op != OCAST)
+ return;
+ if(!nilcast(r->left->type, r->type))
+ return;
+ switch(r->type->etype) {
+ default:
+ return;
+ case TCHAR:
+ case TUCHAR:
+ case TSHORT:
+ case TUSHORT:
+ v = convvtox(l->vconst, r->type->etype);
+ if(v != l->vconst)
+ return;
+ break;
+ }
+ l->type = r->left->type;
+ *r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+ switch(o) {
+ default:
+ diag(Z, "bad in relindex: %O", o);
+ case OEQ: return 0;
+ case ONE: return 1;
+ case OLE: return 2;
+ case OLS: return 3;
+ case OLT: return 4;
+ case OLO: return 5;
+ case OGE: return 6;
+ case OHS: return 7;
+ case OGT: return 8;
+ case OHI: return 9;
+ }
+}
+
+Node*
+invert(Node *n)
+{
+ Node *i;
+
+ if(n == Z || n->op != OLIST)
+ return n;
+ i = n;
+ for(n = n->left; n != Z; n = n->left) {
+ if(n->op != OLIST)
+ break;
+ i->left = n->right;
+ n->right = i;
+ i = n;
+ }
+ i->left = n;
+ return i;
+}
+
+int
+bitno(int32 b)
+{
+ int i;
+
+ for(i=0; i<32; i++)
+ if(b & (1L<<i))
+ return i;
+ diag(Z, "bad in bitno");
+ return 0;
+}
+
+int32
+typebitor(int32 a, int32 b)
+{
+ int32 c;
+
+ c = a | b;
+ if(a & b)
+ if((a & b) == BLONG)
+ c |= BVLONG; /* long long => vlong */
+ else
+ warn(Z, "once is enough: %Q", a & b);
+ return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ if(debug['w']) {
+ Bprint(&diagbuf, "warning: ");
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "warning");
+ }
+}
+
+void
+yyerror(char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ /*
+ * hack to intercept message from yaccpar
+ */
+ if(strcmp(fmt, "syntax error") == 0) {
+ yyerror("syntax error, last name: %s", symb);
+ return;
+ }
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", lineno, buf);
+ nerrors++;
+ if(nerrors > 10) {
+ Bprint(&diagbuf, "too many errors\n");
+ errorexit();
+ }
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+ char buf[STRINGSZ];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+ if(debug['X']){
+ Bflush(&diagbuf);
+ abort();
+ }
+ if(n != Z)
+ if(debug['v'])
+ prtree(n, "diagnostic");
+
+ nerrors++;
+ errorexit();
+}
+
+uint32 thash1 = 0x2edab8c9;
+uint32 thash2 = 0x1dc74fb8;
+uint32 thash3 = 0x1f241331;
+uint32 thash[NALLTYPES];
+Init thashinit[] =
+{
+ TXXX, 0x17527bbd, 0,
+ TCHAR, 0x5cedd32b, 0,
+ TUCHAR, 0x552c4454, 0,
+ TSHORT, 0x63040b4b, 0,
+ TUSHORT, 0x32a45878, 0,
+ TINT, 0x4151d5bd, 0,
+ TUINT, 0x5ae707d6, 0,
+ TLONG, 0x5ef20f47, 0,
+ TULONG, 0x36d8eb8f, 0,
+ TVLONG, 0x6e5e9590, 0,
+ TUVLONG, 0x75910105, 0,
+ TFLOAT, 0x25fd7af1, 0,
+ TDOUBLE, 0x7c40a1b2, 0,
+ TIND, 0x1b832357, 0,
+ TFUNC, 0x6babc9cb, 0,
+ TARRAY, 0x7c50986d, 0,
+ TVOID, 0x44112eff, 0,
+ TSTRUCT, 0x7c2da3bf, 0,
+ TUNION, 0x3eb25e98, 0,
+ TENUM, 0x44b54f61, 0,
+ TFILE, 0x19242ac3, 0,
+ TOLD, 0x22b15988, 0,
+ TDOT, 0x0204f6b3, 0,
+ -1, 0, 0,
+};
+
+char* bnames[NALIGN];
+Init bnamesinit[] =
+{
+ Axxx, 0, "Axxx",
+ Ael1, 0, "el1",
+ Ael2, 0, "el2",
+ Asu2, 0, "su2",
+ Aarg0, 0, "arg0",
+ Aarg1, 0, "arg1",
+ Aarg2, 0, "arg2",
+ Aaut3, 0, "aut3",
+ -1, 0, 0,
+};
+
+char* tnames[NALLTYPES];
+Init tnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ TDOT, 0, "DOT",
+ -1, 0, 0,
+};
+
+char* gnames[NGTYPES];
+Init gnamesinit[] =
+{
+ GXXX, 0, "GXXX",
+ GCONSTNT, 0, "CONST",
+ GVOLATILE, 0, "VOLATILE",
+ GVOLATILE|GCONSTNT, 0, "CONST-VOLATILE",
+ -1, 0, 0,
+};
+
+char* qnames[NALLTYPES];
+Init qnamesinit[] =
+{
+ TXXX, 0, "TXXX",
+ TCHAR, 0, "CHAR",
+ TUCHAR, 0, "UCHAR",
+ TSHORT, 0, "SHORT",
+ TUSHORT, 0, "USHORT",
+ TINT, 0, "INT",
+ TUINT, 0, "UINT",
+ TLONG, 0, "LONG",
+ TULONG, 0, "ULONG",
+ TVLONG, 0, "VLONG",
+ TUVLONG, 0, "UVLONG",
+ TFLOAT, 0, "FLOAT",
+ TDOUBLE, 0, "DOUBLE",
+ TIND, 0, "IND",
+ TFUNC, 0, "FUNC",
+ TARRAY, 0, "ARRAY",
+ TVOID, 0, "VOID",
+ TSTRUCT, 0, "STRUCT",
+ TUNION, 0, "UNION",
+ TENUM, 0, "ENUM",
+
+ TAUTO, 0, "AUTO",
+ TEXTERN, 0, "EXTERN",
+ TSTATIC, 0, "STATIC",
+ TTYPEDEF, 0, "TYPEDEF",
+ TTYPESTR, 0, "TYPESTR",
+ TREGISTER, 0, "REGISTER",
+ TCONSTNT, 0, "CONSTNT",
+ TVOLATILE, 0, "VOLATILE",
+ TUNSIGNED, 0, "UNSIGNED",
+ TSIGNED, 0, "SIGNED",
+ TDOT, 0, "DOT",
+ TFILE, 0, "FILE",
+ TOLD, 0, "OLD",
+ -1, 0, 0,
+};
+char* cnames[NCTYPES];
+Init cnamesinit[] =
+{
+ CXXX, 0, "CXXX",
+ CAUTO, 0, "AUTO",
+ CEXTERN, 0, "EXTERN",
+ CGLOBL, 0, "GLOBL",
+ CSTATIC, 0, "STATIC",
+ CLOCAL, 0, "LOCAL",
+ CTYPEDEF, 0, "TYPEDEF",
+ CTYPESTR, 0, "TYPESTR",
+ CPARAM, 0, "PARAM",
+ CSELEM, 0, "SELEM",
+ CLABEL, 0, "LABEL",
+ CEXREG, 0, "EXREG",
+ -1, 0, 0,
+};
+
+char* onames[OEND+1];
+Init onamesinit[] =
+{
+ OXXX, 0, "OXXX",
+ OADD, 0, "ADD",
+ OADDR, 0, "ADDR",
+ OAND, 0, "AND",
+ OANDAND, 0, "ANDAND",
+ OARRAY, 0, "ARRAY",
+ OAS, 0, "AS",
+ OASI, 0, "ASI",
+ OASADD, 0, "ASADD",
+ OASAND, 0, "ASAND",
+ OASASHL, 0, "ASASHL",
+ OASASHR, 0, "ASASHR",
+ OASDIV, 0, "ASDIV",
+ OASHL, 0, "ASHL",
+ OASHR, 0, "ASHR",
+ OASLDIV, 0, "ASLDIV",
+ OASLMOD, 0, "ASLMOD",
+ OASLMUL, 0, "ASLMUL",
+ OASLSHR, 0, "ASLSHR",
+ OASMOD, 0, "ASMOD",
+ OASMUL, 0, "ASMUL",
+ OASOR, 0, "ASOR",
+ OASSUB, 0, "ASSUB",
+ OASXOR, 0, "ASXOR",
+ OBIT, 0, "BIT",
+ OBREAK, 0, "BREAK",
+ OCASE, 0, "CASE",
+ OCAST, 0, "CAST",
+ OCOMMA, 0, "COMMA",
+ OCOND, 0, "COND",
+ OCONST, 0, "CONST",
+ OCONTINUE, 0, "CONTINUE",
+ ODIV, 0, "DIV",
+ ODOT, 0, "DOT",
+ ODOTDOT, 0, "DOTDOT",
+ ODWHILE, 0, "DWHILE",
+ OENUM, 0, "ENUM",
+ OEQ, 0, "EQ",
+ OEXREG, 0, "EXREG",
+ OFOR, 0, "FOR",
+ OFUNC, 0, "FUNC",
+ OGE, 0, "GE",
+ OGOTO, 0, "GOTO",
+ OGT, 0, "GT",
+ OHI, 0, "HI",
+ OHS, 0, "HS",
+ OIF, 0, "IF",
+ OIND, 0, "IND",
+ OINDREG, 0, "INDREG",
+ OINIT, 0, "INIT",
+ OLABEL, 0, "LABEL",
+ OLDIV, 0, "LDIV",
+ OLE, 0, "LE",
+ OLIST, 0, "LIST",
+ OLMOD, 0, "LMOD",
+ OLMUL, 0, "LMUL",
+ OLO, 0, "LO",
+ OLS, 0, "LS",
+ OLSHR, 0, "LSHR",
+ OLT, 0, "LT",
+ OMOD, 0, "MOD",
+ OMUL, 0, "MUL",
+ ONAME, 0, "NAME",
+ ONE, 0, "NE",
+ ONOT, 0, "NOT",
+ OOR, 0, "OR",
+ OOROR, 0, "OROR",
+ OPOSTDEC, 0, "POSTDEC",
+ OPOSTINC, 0, "POSTINC",
+ OPREDEC, 0, "PREDEC",
+ OPREINC, 0, "PREINC",
+ OPROTO, 0, "PROTO",
+ OREGISTER, 0, "REGISTER",
+ ORETURN, 0, "RETURN",
+ OSET, 0, "SET",
+ OSIGN, 0, "SIGN",
+ OSIZE, 0, "SIZE",
+ OSTRING, 0, "STRING",
+ OLSTRING, 0, "LSTRING",
+ OSTRUCT, 0, "STRUCT",
+ OSUB, 0, "SUB",
+ OSWITCH, 0, "SWITCH",
+ OUNION, 0, "UNION",
+ OUSED, 0, "USED",
+ OWHILE, 0, "WHILE",
+ OXOR, 0, "XOR",
+ OPOS, 0, "POS",
+ ONEG, 0, "NEG",
+ OCOM, 0, "COM",
+ OELEM, 0, "ELEM",
+ OTST, 0, "TST",
+ OINDEX, 0, "INDEX",
+ OFAS, 0, "FAS",
+ OREGPAIR, 0, "REGPAIR",
+ OEND, 0, "END",
+ -1, 0, 0,
+};
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+uchar comrel[12] =
+{
+ ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+uchar invrel[12] =
+{
+ OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+uchar logrel[12] =
+{
+ OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+uchar typei[NTYPE];
+int typeiinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+uchar typeu[NTYPE];
+int typeuinit[] =
+{
+ TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+uchar typesuv[NTYPE];
+int typesuvinit[] =
+{
+ TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+uchar typeilp[NTYPE];
+int typeilpinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+uchar typechl[NTYPE];
+uchar typechlv[NTYPE];
+uchar typechlvp[NTYPE];
+int typechlinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typechlp[NTYPE];
+int typechlpinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+uchar typechlpfd[NTYPE];
+int typechlpfdinit[] =
+{
+ TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+uchar typec[NTYPE];
+int typecinit[] =
+{
+ TCHAR, TUCHAR, -1
+};
+
+uchar typeh[NTYPE];
+int typehinit[] =
+{
+ TSHORT, TUSHORT, -1,
+};
+
+uchar typeil[NTYPE];
+int typeilinit[] =
+{
+ TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar typev[NTYPE];
+int typevinit[] =
+{
+ TVLONG, TUVLONG, -1,
+};
+
+uchar typefd[NTYPE];
+int typefdinit[] =
+{
+ TFLOAT, TDOUBLE, -1,
+};
+
+uchar typeaf[NTYPE];
+int typeafinit[] =
+{
+ TFUNC, TARRAY, -1,
+};
+
+uchar typesu[NTYPE];
+int typesuinit[] =
+{
+ TSTRUCT, TUNION, -1,
+};
+
+int32 tasign[NTYPE];
+Init tasigninit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ TSTRUCT, BSTRUCT, 0,
+ TUNION, BUNION, 0,
+ -1, 0, 0,
+};
+
+int32 tasadd[NTYPE];
+Init tasaddinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 tcast[NTYPE];
+Init tcastinit[] =
+{
+ TCHAR, BNUMBER|BIND|BVOID, 0,
+ TUCHAR, BNUMBER|BIND|BVOID, 0,
+ TSHORT, BNUMBER|BIND|BVOID, 0,
+ TUSHORT, BNUMBER|BIND|BVOID, 0,
+ TINT, BNUMBER|BIND|BVOID, 0,
+ TUINT, BNUMBER|BIND|BVOID, 0,
+ TLONG, BNUMBER|BIND|BVOID, 0,
+ TULONG, BNUMBER|BIND|BVOID, 0,
+ TVLONG, BNUMBER|BIND|BVOID, 0,
+ TUVLONG, BNUMBER|BIND|BVOID, 0,
+ TFLOAT, BNUMBER|BVOID, 0,
+ TDOUBLE, BNUMBER|BVOID, 0,
+ TIND, BINTEGER|BIND|BVOID, 0,
+ TVOID, BVOID, 0,
+ TSTRUCT, BSTRUCT|BVOID, 0,
+ TUNION, BUNION|BVOID, 0,
+ -1, 0, 0,
+};
+
+int32 tadd[NTYPE];
+Init taddinit[] =
+{
+ TCHAR, BNUMBER|BIND, 0,
+ TUCHAR, BNUMBER|BIND, 0,
+ TSHORT, BNUMBER|BIND, 0,
+ TUSHORT, BNUMBER|BIND, 0,
+ TINT, BNUMBER|BIND, 0,
+ TUINT, BNUMBER|BIND, 0,
+ TLONG, BNUMBER|BIND, 0,
+ TULONG, BNUMBER|BIND, 0,
+ TVLONG, BNUMBER|BIND, 0,
+ TUVLONG, BNUMBER|BIND, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 tsub[NTYPE];
+Init tsubinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BINTEGER|BIND, 0,
+ -1, 0, 0,
+};
+
+int32 tmul[NTYPE];
+Init tmulinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ -1, 0, 0,
+};
+
+int32 tand[NTYPE];
+Init tandinit[] =
+{
+ TCHAR, BINTEGER, 0,
+ TUCHAR, BINTEGER, 0,
+ TSHORT, BINTEGER, 0,
+ TUSHORT, BINTEGER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BINTEGER, 0,
+ TULONG, BINTEGER, 0,
+ TVLONG, BINTEGER, 0,
+ TUVLONG, BINTEGER, 0,
+ -1, 0, 0,
+};
+
+int32 trel[NTYPE];
+Init trelinit[] =
+{
+ TCHAR, BNUMBER, 0,
+ TUCHAR, BNUMBER, 0,
+ TSHORT, BNUMBER, 0,
+ TUSHORT, BNUMBER, 0,
+ TINT, BNUMBER, 0,
+ TUINT, BNUMBER, 0,
+ TLONG, BNUMBER, 0,
+ TULONG, BNUMBER, 0,
+ TVLONG, BNUMBER, 0,
+ TUVLONG, BNUMBER, 0,
+ TFLOAT, BNUMBER, 0,
+ TDOUBLE, BNUMBER, 0,
+ TIND, BIND, 0,
+ -1, 0, 0,
+};
+
+int32 tfunct[1] =
+{
+ BFUNC,
+};
+
+int32 tindir[1] =
+{
+ BIND,
+};
+
+int32 tdot[1] =
+{
+ BSTRUCT|BUNION,
+};
+
+int32 tnot[1] =
+{
+ BNUMBER|BIND,
+};
+
+int32 targ[1] =
+{
+ BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+uchar tab[NTYPE][NTYPE] =
+{
+/*TXXX*/ { 0,
+ },
+
+/*TCHAR*/ { 0, TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUCHAR*/ { 0, TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TSHORT*/ { 0, TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUSHORT*/ { 0, TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TINT*/ { 0, TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUINT*/ { 0, TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TLONG*/ { 0, TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+ TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TULONG*/ { 0, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+ TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TVLONG*/ { 0, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+ TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TUVLONG*/ { 0, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+ TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+ },
+/*TFLOAT*/ { 0, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+ TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+ },
+/*TDOUBLE*/ { 0, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+ TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+ },
+/*TIND*/ { 0, TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+ TIND, TIND, TIND, TIND, TIND, TIND,
+ },
+};
+
+void
+urk(char *name, int max, int i)
+{
+ if(i >= max) {
+ fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+ exits("init");
+ }
+}
+
+void
+tinit(void)
+{
+ int *ip;
+ Init *p;
+
+ for(p=thashinit; p->code >= 0; p++) {
+ urk("thash", nelem(thash), p->code);
+ thash[p->code] = p->value;
+ }
+ for(p=bnamesinit; p->code >= 0; p++) {
+ urk("bnames", nelem(bnames), p->code);
+ bnames[p->code] = p->s;
+ }
+ for(p=tnamesinit; p->code >= 0; p++) {
+ urk("tnames", nelem(tnames), p->code);
+ tnames[p->code] = p->s;
+ }
+ for(p=gnamesinit; p->code >= 0; p++) {
+ urk("gnames", nelem(gnames), p->code);
+ gnames[p->code] = p->s;
+ }
+ for(p=qnamesinit; p->code >= 0; p++) {
+ urk("qnames", nelem(qnames), p->code);
+ qnames[p->code] = p->s;
+ }
+ for(p=cnamesinit; p->code >= 0; p++) {
+ urk("cnames", nelem(cnames), p->code);
+ cnames[p->code] = p->s;
+ }
+ for(p=onamesinit; p->code >= 0; p++) {
+ urk("onames", nelem(onames), p->code);
+ onames[p->code] = p->s;
+ }
+ for(ip=typeiinit; *ip>=0; ip++) {
+ urk("typei", nelem(typei), *ip);
+ typei[*ip] = 1;
+ }
+ for(ip=typeuinit; *ip>=0; ip++) {
+ urk("typeu", nelem(typeu), *ip);
+ typeu[*ip] = 1;
+ }
+ for(ip=typesuvinit; *ip>=0; ip++) {
+ urk("typesuv", nelem(typesuv), *ip);
+ typesuv[*ip] = 1;
+ }
+ for(ip=typeilpinit; *ip>=0; ip++) {
+ urk("typeilp", nelem(typeilp), *ip);
+ typeilp[*ip] = 1;
+ }
+ for(ip=typechlinit; *ip>=0; ip++) {
+ urk("typechl", nelem(typechl), *ip);
+ typechl[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpinit; *ip>=0; ip++) {
+ urk("typechlp", nelem(typechlp), *ip);
+ typechlp[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typechlpfdinit; *ip>=0; ip++) {
+ urk("typechlpfd", nelem(typechlpfd), *ip);
+ typechlpfd[*ip] = 1;
+ }
+ for(ip=typecinit; *ip>=0; ip++) {
+ urk("typec", nelem(typec), *ip);
+ typec[*ip] = 1;
+ }
+ for(ip=typehinit; *ip>=0; ip++) {
+ urk("typeh", nelem(typeh), *ip);
+ typeh[*ip] = 1;
+ }
+ for(ip=typeilinit; *ip>=0; ip++) {
+ urk("typeil", nelem(typeil), *ip);
+ typeil[*ip] = 1;
+ }
+ for(ip=typevinit; *ip>=0; ip++) {
+ urk("typev", nelem(typev), *ip);
+ typev[*ip] = 1;
+ typechlv[*ip] = 1;
+ typechlvp[*ip] = 1;
+ }
+ for(ip=typefdinit; *ip>=0; ip++) {
+ urk("typefd", nelem(typefd), *ip);
+ typefd[*ip] = 1;
+ }
+ for(ip=typeafinit; *ip>=0; ip++) {
+ urk("typeaf", nelem(typeaf), *ip);
+ typeaf[*ip] = 1;
+ }
+ for(ip=typesuinit; *ip >= 0; ip++) {
+ urk("typesu", nelem(typesu), *ip);
+ typesu[*ip] = 1;
+ }
+ for(p=tasigninit; p->code >= 0; p++) {
+ urk("tasign", nelem(tasign), p->code);
+ tasign[p->code] = p->value;
+ }
+ for(p=tasaddinit; p->code >= 0; p++) {
+ urk("tasadd", nelem(tasadd), p->code);
+ tasadd[p->code] = p->value;
+ }
+ for(p=tcastinit; p->code >= 0; p++) {
+ urk("tcast", nelem(tcast), p->code);
+ tcast[p->code] = p->value;
+ }
+ for(p=taddinit; p->code >= 0; p++) {
+ urk("tadd", nelem(tadd), p->code);
+ tadd[p->code] = p->value;
+ }
+ for(p=tsubinit; p->code >= 0; p++) {
+ urk("tsub", nelem(tsub), p->code);
+ tsub[p->code] = p->value;
+ }
+ for(p=tmulinit; p->code >= 0; p++) {
+ urk("tmul", nelem(tmul), p->code);
+ tmul[p->code] = p->value;
+ }
+ for(p=tandinit; p->code >= 0; p++) {
+ urk("tand", nelem(tand), p->code);
+ tand[p->code] = p->value;
+ }
+ for(p=trelinit; p->code >= 0; p++) {
+ urk("trel", nelem(trel), p->code);
+ trel[p->code] = p->value;
+ }
+
+ /* 32-bit defaults */
+ typeword = typechlp;
+ typecmplx = typesuv;
+}
+
+/*
+ * return 1 if it is impossible to jump into the middle of n.
+ */
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+ if(n == Z)
+ return 1;
+ switch(n->op) {
+ case OLIST:
+ if(!deadhead(n->left, caseok))
+ return 0;
+ rloop:
+ n = n->right;
+ goto loop;
+
+ case ORETURN:
+ break;
+
+ case OLABEL:
+ return 0;
+
+ case OGOTO:
+ break;
+
+ case OCASE:
+ if(!caseok)
+ return 0;
+ goto rloop;
+
+ case OSWITCH:
+ return deadhead(n->right, 1);
+
+ case OWHILE:
+ case ODWHILE:
+ goto rloop;
+
+ case OFOR:
+ goto rloop;
+
+ case OCONTINUE:
+ break;
+
+ case OBREAK:
+ break;
+
+ case OIF:
+ return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+ case OSET:
+ case OUSED:
+ break;
+ }
+ return 1;
+}
+
+int
+deadheads(Node *c)
+{
+ return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+mixedasop(Type *l, Type *r)
+{
+ return !typefd[l->etype] && typefd[r->etype];
+}