summaryrefslogtreecommitdiff
path: root/src/cmd/cc/com.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/cc/com.c')
-rw-r--r--src/cmd/cc/com.c1385
1 files changed, 1385 insertions, 0 deletions
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
new file mode 100644
index 000000000..6e470ee64
--- /dev/null
+++ b/src/cmd/cc/com.c
@@ -0,0 +1,1385 @@
+// Inferno utils/cc/com.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.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"
+
+int compar(Node*, int);
+
+void
+complex(Node *n)
+{
+
+ if(n == Z)
+ return;
+
+ nearln = n->lineno;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "pre complex");
+ if(tcom(n))
+ return;
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "t complex");
+ ccom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "c complex");
+ acom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "a complex");
+ xcom(n);
+ if(debug['t'])
+ if(n->op != OCONST)
+ prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+ ADDROF = 1<<0,
+ CASTOF = 1<<1,
+ ADDROP = 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+ return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+ Node *l, *r;
+ Type *t;
+ int o;
+
+ if(n == Z) {
+ diag(Z, "Z in tcom");
+ errorexit();
+ }
+ n->addable = 0;
+ l = n->left;
+ r = n->right;
+
+ switch(n->op) {
+ default:
+ diag(n, "unknown op in type complex: %O", n->op);
+ goto bad;
+
+ case ODOTDOT:
+ /*
+ * tcom has already been called on this subtree
+ */
+ *n = *n->left;
+ if(n->type == T)
+ goto bad;
+ break;
+
+ case OCAST:
+ if(n->type == T)
+ break;
+ if(n->type->width == types[TLONG]->width) {
+ if(tcomo(l, ADDROF|CASTOF))
+ goto bad;
+ } else
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, n->type, tcast))
+ goto bad;
+ break;
+
+ case ORETURN:
+ if(l == Z) {
+ if(n->type->etype != TVOID)
+ diag(n, "null return of a typed function");
+ break;
+ }
+ if(tcom(l))
+ goto bad;
+ typeext(n->type, l);
+ if(tcompat(n, n->type, l->type, tasign))
+ break;
+ constas(n, n->type, l->type);
+ if(!sametype(n->type, l->type)) {
+ l = new1(OCAST, l, Z);
+ l->type = n->type;
+ n->left = l;
+ }
+ break;
+
+ case OASI: /* same as as, but no test for const */
+ n->op = OAS;
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+
+ typeext(l->type, r);
+ if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OAS:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ if(tcompat(n, l->type, r->type, tasign))
+ goto bad;
+ constas(n, l->type, r->type);
+ if(!sametype(l->type, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = l->type;
+ n->right = r;
+ }
+ n->type = l->type;
+ break;
+
+ case OASADD:
+ case OASSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tasadd))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ break;
+
+ case OASMUL:
+ case OASLMUL:
+ case OASDIV:
+ case OASLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ constas(n, l->type, r->type);
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASDIV)
+ n->op = OASLDIV;
+ if(n->op == OASMUL)
+ n->op = OASLMUL;
+ }
+ break;
+
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->type = l->type;
+ if(typeu[n->type->etype]) {
+ if(n->op == OASASHR)
+ n->op = OASLSHR;
+ }
+ break;
+
+ case OASMOD:
+ case OASLMOD:
+ case OASOR:
+ case OASAND:
+ case OASXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ t = l->type;
+ arith(n, 0);
+ while(n->left->op == OCAST)
+ n->left = n->left->left;
+ if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+ r = new1(OCAST, n->right, Z);
+ r->type = t;
+ n->right = r;
+ n->type = t;
+ }
+ if(typeu[n->type->etype]) {
+ if(n->op == OASMOD)
+ n->op = OASLMOD;
+ }
+ break;
+
+ case OPREINC:
+ case OPREDEC:
+ case OPOSTINC:
+ case OPOSTDEC:
+ if(tcom(l))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, types[TINT], tadd))
+ goto bad;
+ n->type = l->type;
+ if(n->type->etype == TIND)
+ if(n->type->link->width < 1)
+ diag(n, "inc/dec of a void pointer");
+ break;
+
+ case OEQ:
+ case ONE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext(l->type, r);
+ typeext(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ n->type = types[TINT];
+ break;
+
+ case OLT:
+ case OGE:
+ case OGT:
+ case OLE:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ typeext1(l->type, r);
+ typeext1(r->type, l);
+ if(tcompat(n, l->type, r->type, trel))
+ goto bad;
+ arith(n, 0);
+ if(typeu[n->type->etype])
+ n->op = logrel[relindex(n->op)];
+ n->type = types[TINT];
+ break;
+
+ case OCOND:
+ o = tcom(l);
+ o |= tcom(r->left);
+ if(o | tcom(r->right))
+ goto bad;
+ if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+ r->left->type = r->right->type;
+ r->left->vconst = 0;
+ }
+ if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+ r->right->type = r->left->type;
+ r->right->vconst = 0;
+ }
+ if(sametype(r->right->type, r->left->type)) {
+ r->type = r->right->type;
+ n->type = r->type;
+ break;
+ }
+ if(tcompat(r, r->left->type, r->right->type, trel))
+ goto bad;
+ arith(r, 0);
+ n->type = r->type;
+ break;
+
+ case OADD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tadd))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OSUB:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMUL:
+ case OLMUL:
+ case ODIV:
+ case OLDIV:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tmul))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype]) {
+ if(n->op == ODIV)
+ n->op = OLDIV;
+ if(n->op == OMUL)
+ n->op = OLMUL;
+ }
+ break;
+
+ case OLSHR:
+ case OASHL:
+ case OASHR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ n->right = Z;
+ arith(n, 1);
+ n->right = new1(OCAST, r, Z);
+ n->right->type = types[TINT];
+ if(typeu[n->type->etype])
+ if(n->op == OASHR)
+ n->op = OLSHR;
+ break;
+
+ case OAND:
+ case OOR:
+ case OXOR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case OMOD:
+ case OLMOD:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ arith(n, 1);
+ if(typeu[n->type->etype])
+ n->op = OLMOD;
+ break;
+
+ case OPOS:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OADD;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ arith(n, 1);
+ break;
+
+ case ONEG:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = 0;
+ l->type = types[TINT];
+ n->op = OSUB;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tsub))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case OCOM:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+
+ if(!machcap(n)) {
+ r = l;
+ l = new(OCONST, Z, Z);
+ l->vconst = -1;
+ l->type = types[TINT];
+ n->op = OXOR;
+ n->right = r;
+ n->left = l;
+
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, l->type, r->type, tand))
+ goto bad;
+ }
+ arith(n, 1);
+ break;
+
+ case ONOT:
+ if(tcom(l))
+ goto bad;
+ if(isfunct(n))
+ break;
+ if(tcompat(n, T, l->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OANDAND:
+ case OOROR:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ if(tcompat(n, T, l->type, tnot) |
+ tcompat(n, T, r->type, tnot))
+ goto bad;
+ n->type = types[TINT];
+ break;
+
+ case OCOMMA:
+ o = tcom(l);
+ if(o | tcom(r))
+ goto bad;
+ n->type = r->type;
+ break;
+
+
+ case OSIGN: /* extension signof(type) returns a hash */
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "signof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width < 0) {
+ diag(n, "signof undefined type");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(signature(n->type), TULONG);
+ n->type = types[TULONG];
+ break;
+
+ case OSIZE:
+ if(l != Z) {
+ if(l->op != OSTRING && l->op != OLSTRING)
+ if(tcomo(l, 0))
+ goto bad;
+ if(l->op == OBIT) {
+ diag(n, "sizeof bitfield");
+ goto bad;
+ }
+ n->type = l->type;
+ }
+ if(n->type == T)
+ goto bad;
+ if(n->type->width <= 0) {
+ diag(n, "sizeof undefined type");
+ goto bad;
+ }
+ if(n->type->etype == TFUNC) {
+ diag(n, "sizeof function");
+ goto bad;
+ }
+ n->op = OCONST;
+ n->left = Z;
+ n->right = Z;
+ n->vconst = convvtox(n->type->width, TINT);
+ n->type = types[TINT];
+ break;
+
+ case OFUNC:
+ o = tcomo(l, 0);
+ if(o)
+ goto bad;
+ if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+ l = new1(OIND, l, Z);
+ l->type = l->left->type->link;
+ n->left = l;
+ }
+ if(tcompat(n, T, l->type, tfunct))
+ goto bad;
+ if(o | tcoma(l, r, l->type->down, 1))
+ goto bad;
+ n->type = l->type->link;
+ if(!debug['B'])
+ if(l->type->down == T || l->type->down->etype == TOLD) {
+ nerrors--;
+ diag(n, "function args not checked: %F", l);
+ }
+ dpcheck(n);
+ break;
+
+ case ONAME:
+ if(n->type == T) {
+ diag(n, "name not declared: %F", n);
+ goto bad;
+ }
+ if(n->type->etype == TENUM) {
+ n->op = OCONST;
+ n->type = n->sym->tenum;
+ if(!typefd[n->type->etype])
+ n->vconst = n->sym->vconst;
+ else
+ n->fconst = n->sym->fconst;
+ break;
+ }
+ n->addable = 1;
+ if(n->class == CEXREG) {
+ n->op = OREGISTER;
+ // on 386 or amd64, "extern register" generates
+ // memory references relative to the
+ // gs or fs segment.
+ if(thechar == '8' || thechar == '6') // [sic]
+ n->op = OEXREG;
+ n->reg = n->sym->offset;
+ n->xoffset = 0;
+ break;
+ }
+ break;
+
+ case OLSTRING:
+ if(n->type->link != types[TUSHORT]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ ushort a[1];
+ a[0] = 0;
+ outlstring(a, sizeof(ushort));
+ o = outlstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outlstring(n->rstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OSTRING:
+ if(n->type->link != types[TCHAR]) {
+ o = outstring(0, 0);
+ while(o & 3) {
+ outstring("", 1);
+ o = outstring(0, 0);
+ }
+ }
+ n->op = ONAME;
+ n->xoffset = outstring(n->cstring, n->type->width);
+ n->addable = 1;
+ break;
+
+ case OCONST:
+ break;
+
+ case ODOT:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tdot))
+ goto bad;
+ if(tcomd(n))
+ goto bad;
+ break;
+
+ case OADDR:
+ if(tcomo(l, ADDROP))
+ goto bad;
+ if(tlvalue(l))
+ goto bad;
+ if(l->type->nbits) {
+ diag(n, "address of a bit field");
+ goto bad;
+ }
+ if(l->op == OREGISTER) {
+ diag(n, "address of a register");
+ goto bad;
+ }
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ break;
+
+ case OIND:
+ if(tcom(l))
+ goto bad;
+ if(tcompat(n, T, l->type, tindir))
+ goto bad;
+ n->type = l->type->link;
+ n->addable = 1;
+ break;
+
+ case OSTRUCT:
+ if(tcomx(n))
+ goto bad;
+ break;
+ }
+ t = n->type;
+ if(t == T)
+ goto bad;
+ if(t->width < 0) {
+ snap(t);
+ if(t->width < 0) {
+ if(typesu[t->etype] && t->tag)
+ diag(n, "structure not fully declared %s", t->tag->name);
+ else
+ diag(n, "structure not fully declared");
+ goto bad;
+ }
+ }
+ if(typeaf[t->etype]) {
+ if(f & ADDROF)
+ goto addaddr;
+ if(f & ADDROP)
+ warn(n, "address of array/func ignored");
+ }
+ return 0;
+
+addaddr:
+ if(tlvalue(n))
+ goto bad;
+ l = new1(OXXX, Z, Z);
+ *l = *n;
+ n->op = OADDR;
+ if(l->type->etype == TARRAY)
+ l->type = l->type->link;
+ n->left = l;
+ n->right = Z;
+ n->addable = 0;
+ n->type = typ(TIND, l->type);
+ n->type->width = types[TIND]->width;
+ return 0;
+
+bad:
+ n->type = T;
+ return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+ Node *n1;
+ int o;
+
+ if(t != T)
+ if(t->etype == TOLD || t->etype == TDOT) /* .../old in prototype */
+ t = T;
+ if(n == Z) {
+ if(t != T && !sametype(t, types[TVOID])) {
+ diag(n, "not enough function arguments: %F", l);
+ return 1;
+ }
+ return 0;
+ }
+ if(n->op == OLIST) {
+ o = tcoma(l, n->left, t, 0);
+ if(t != T) {
+ t = t->down;
+ if(t == T)
+ t = types[TVOID];
+ }
+ return o | tcoma(l, n->right, t, 1);
+ }
+ if(f && t != T)
+ tcoma(l, Z, t->down, 0);
+ if(tcom(n) || tcompat(n, T, n->type, targ))
+ return 1;
+ if(sametype(t, types[TVOID])) {
+ diag(n, "too many function arguments: %F", l);
+ return 1;
+ }
+ if(t != T) {
+ typeext(t, n);
+ if(stcompat(nodproto, t, n->type, tasign)) {
+ diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+ n->type, t, l);
+ return 1;
+ }
+// switch(t->etype) {
+// case TCHAR:
+// case TSHORT:
+// t = types[TINT];
+// break;
+//
+// case TUCHAR:
+// case TUSHORT:
+// t = types[TUINT];
+// break;
+// }
+ } else {
+ switch(n->type->etype) {
+ case TCHAR:
+ case TSHORT:
+ t = types[TINT];
+ break;
+
+ case TUCHAR:
+ case TUSHORT:
+ t = types[TUINT];
+ break;
+
+ case TFLOAT:
+ t = types[TDOUBLE];
+ }
+ }
+
+ if(t != T && !sametype(t, n->type)) {
+ n1 = new1(OXXX, Z, Z);
+ *n1 = *n;
+ n->op = OCAST;
+ n->left = n1;
+ n->right = Z;
+ n->type = t;
+ n->addable = 0;
+ }
+ return 0;
+}
+
+int
+tcomd(Node *n)
+{
+ Type *t;
+ int32 o;
+
+ o = 0;
+ t = dotsearch(n->sym, n->left->type->link, n, &o);
+ if(t == T) {
+ diag(n, "not a member of struct/union: %F", n);
+ return 1;
+ }
+ makedot(n, t, o);
+ return 0;
+}
+
+int
+tcomx(Node *n)
+{
+ Type *t;
+ Node *l, *r, **ar, **al;
+ int e;
+
+ e = 0;
+ if(n->type->etype != TSTRUCT) {
+ diag(n, "constructor must be a structure");
+ return 1;
+ }
+ l = invert(n->left);
+ n->left = l;
+ al = &n->left;
+ for(t = n->type->link; t != T; t = t->down) {
+ if(l == Z) {
+ diag(n, "constructor list too short");
+ return 1;
+ }
+ if(l->op == OLIST) {
+ r = l->left;
+ ar = &l->left;
+ al = &l->right;
+ l = l->right;
+ } else {
+ r = l;
+ ar = al;
+ l = Z;
+ }
+ if(tcom(r))
+ e++;
+ typeext(t, r);
+ if(tcompat(n, t, r->type, tasign))
+ e++;
+ constas(n, t, r->type);
+ if(!e && !sametype(t, r->type)) {
+ r = new1(OCAST, r, Z);
+ r->type = t;
+ *ar = r;
+ }
+ }
+ if(l != Z) {
+ diag(n, "constructor list too long");
+ return 1;
+ }
+ return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+ if(!n->addable) {
+ diag(n, "not an l-value");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * general rewrite
+ * (IND(ADDR x)) ==> x
+ * (ADDR(IND x)) ==> x
+ * remove some zero operands
+ * remove no op casts
+ * evaluate constants
+ */
+void
+ccom(Node *n)
+{
+ Node *l, *r;
+ int t;
+
+loop:
+ if(n == Z)
+ return;
+ l = n->left;
+ r = n->right;
+ switch(n->op) {
+
+ case OAS:
+ case OASXOR:
+ case OASAND:
+ case OASOR:
+ case OASMOD:
+ case OASLMOD:
+ case OASLSHR:
+ case OASASHR:
+ case OASASHL:
+ case OASDIV:
+ case OASLDIV:
+ case OASMUL:
+ case OASLMUL:
+ case OASSUB:
+ case OASADD:
+ ccom(l);
+ ccom(r);
+ if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst < 0)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ break;
+
+ case OCAST:
+ ccom(l);
+ if(l->op == OCONST) {
+ evconst(n);
+ if(n->op == OCONST)
+ break;
+ }
+ if(nocast(l->type, n->type)) {
+ l->type = n->type;
+ *n = *l;
+ }
+ break;
+
+ case OCOND:
+ ccom(l);
+ ccom(r);
+ if(l->op == OCONST)
+ if(vconst(l) == 0)
+ *n = *r->right;
+ else
+ *n = *r->left;
+ break;
+
+ case OREGISTER:
+ case OINDREG:
+ case OCONST:
+ case ONAME:
+ break;
+
+ case OADDR:
+ ccom(l);
+ l->etype = TVOID;
+ if(l->op == OIND) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OIND:
+ ccom(l);
+ if(l->op == OADDR) {
+ l->left->type = n->type;
+ *n = *l->left;
+ break;
+ }
+ goto common;
+
+ case OEQ:
+ case ONE:
+
+ case OLE:
+ case OGE:
+ case OLT:
+ case OGT:
+
+ case OLS:
+ case OHS:
+ case OLO:
+ case OHI:
+ ccom(l);
+ ccom(r);
+ if(compar(n, 0) || compar(n, 1))
+ break;
+ relcon(l, r);
+ relcon(r, l);
+ goto common;
+
+ case OASHR:
+ case OASHL:
+ case OLSHR:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ if(r->op == OCONST) {
+ t = n->type->width * 8; /* bits per byte */
+ if(r->vconst >= t || r->vconst <= -t)
+ warn(n, "stupid shift: %lld", r->vconst);
+ }
+ goto common;
+
+ case OMUL:
+ case OLMUL:
+ ccom(l);
+ t = vconst(l);
+ if(t == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(t == 1) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case ODIV:
+ case OLDIV:
+ ccom(l);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ t = vconst(r);
+ if(t == 0) {
+ diag(n, "divide check");
+ *n = *r;
+ break;
+ }
+ if(t == 1) {
+ *n = *l;
+ break;
+ }
+ goto common;
+
+ case OSUB:
+ ccom(r);
+ if(r->op == OCONST) {
+ if(typefd[r->type->etype]) {
+ n->op = OADD;
+ r->fconst = -r->fconst;
+ goto loop;
+ } else {
+ n->op = OADD;
+ r->vconst = -r->vconst;
+ goto loop;
+ }
+ }
+ ccom(l);
+ goto common;
+
+ case OXOR:
+ case OOR:
+ case OADD:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *r;
+ goto loop;
+ }
+ ccom(r);
+ if(vconst(r) == 0) {
+ *n = *l;
+ break;
+ }
+ goto commute;
+
+ case OAND:
+ ccom(l);
+ ccom(r);
+ if(vconst(l) == 0 && !side(r)) {
+ *n = *l;
+ break;
+ }
+ if(vconst(r) == 0 && !side(l)) {
+ *n = *r;
+ break;
+ }
+
+ commute:
+ /* look for commutative constant */
+ if(r->op == OCONST) {
+ if(l->op == n->op) {
+ if(l->left->op == OCONST) {
+ n->right = l->right;
+ l->right = r;
+ goto loop;
+ }
+ if(l->right->op == OCONST) {
+ n->right = l->left;
+ l->left = r;
+ goto loop;
+ }
+ }
+ }
+ if(l->op == OCONST) {
+ if(r->op == n->op) {
+ if(r->left->op == OCONST) {
+ n->left = r->right;
+ r->right = l;
+ goto loop;
+ }
+ if(r->right->op == OCONST) {
+ n->left = r->left;
+ r->left = l;
+ goto loop;
+ }
+ }
+ }
+ goto common;
+
+ case OANDAND:
+ ccom(l);
+ if(vconst(l) == 0) {
+ *n = *l;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ case OOROR:
+ ccom(l);
+ if(l->op == OCONST && l->vconst != 0) {
+ *n = *l;
+ n->vconst = 1;
+ break;
+ }
+ ccom(r);
+ goto common;
+
+ default:
+ if(l != Z)
+ ccom(l);
+ if(r != Z)
+ ccom(r);
+ common:
+ if(l != Z)
+ if(l->op != OCONST)
+ break;
+ if(r != Z)
+ if(r->op != OCONST)
+ break;
+ evconst(n);
+ }
+}
+
+/* OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+static char *cmps[12] =
+{
+ "==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
+};
+
+/* 128-bit numbers */
+typedef struct Big Big;
+struct Big
+{
+ vlong a;
+ uvlong b;
+};
+static int
+cmp(Big x, Big y)
+{
+ if(x.a != y.a){
+ if(x.a < y.a)
+ return -1;
+ return 1;
+ }
+ if(x.b != y.b){
+ if(x.b < y.b)
+ return -1;
+ return 1;
+ }
+ return 0;
+}
+static Big
+add(Big x, int y)
+{
+ uvlong ob;
+
+ ob = x.b;
+ x.b += y;
+ if(y > 0 && x.b < ob)
+ x.a++;
+ if(y < 0 && x.b > ob)
+ x.a--;
+ return x;
+}
+
+Big
+big(vlong a, uvlong b)
+{
+ Big x;
+
+ x.a = a;
+ x.b = b;
+ return x;
+}
+
+int
+compar(Node *n, int reverse)
+{
+ Big lo, hi, x;
+ int op;
+ char xbuf[40], cmpbuf[50];
+ Node *l, *r;
+ Type *lt, *rt;
+
+ /*
+ * The point of this function is to diagnose comparisons
+ * that can never be true or that look misleading because
+ * of the `usual arithmetic conversions'. As an example
+ * of the latter, if x is a ulong, then if(x <= -1) really means
+ * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
+ * what it says (but 8c compiles it wrong anyway).
+ */
+
+ if(reverse){
+ r = n->left;
+ l = n->right;
+ op = comrel[relindex(n->op)];
+ }else{
+ l = n->left;
+ r = n->right;
+ op = n->op;
+ }
+
+ /*
+ * Skip over left casts to find out the original expression range.
+ */
+ while(l->op == OCAST)
+ l = l->left;
+ if(l->op == OCONST)
+ return 0;
+ lt = l->type;
+ if(l->op == ONAME && l->sym->type){
+ lt = l->sym->type;
+ if(lt->etype == TARRAY)
+ lt = lt->link;
+ }
+ if(lt == T)
+ return 0;
+ if(lt->etype == TXXX || lt->etype > TUVLONG)
+ return 0;
+
+ /*
+ * Skip over the right casts to find the on-screen value.
+ */
+ if(r->op != OCONST)
+ return 0;
+ while(r->oldop == OCAST && !r->xcast)
+ r = r->left;
+ rt = r->type;
+ if(rt == T)
+ return 0;
+
+ x.b = r->vconst;
+ x.a = 0;
+ if((rt->etype&1) && r->vconst < 0) /* signed negative */
+ x.a = ~0ULL;
+
+ if((lt->etype&1)==0){
+ /* unsigned */
+ lo = big(0, 0);
+ if(lt->width == 8)
+ hi = big(0, ~0ULL);
+ else
+ hi = big(0, (1LL<<(l->type->width*8))-1);
+ }else{
+ lo = big(~0ULL, -(1LL<<(l->type->width*8-1)));
+ hi = big(0, (1LL<<(l->type->width*8-1))-1);
+ }
+
+ switch(op){
+ case OLT:
+ case OLO:
+ case OGE:
+ case OHS:
+ if(cmp(x, lo) <= 0)
+ goto useless;
+ if(cmp(x, add(hi, 1)) >= 0)
+ goto useless;
+ break;
+ case OLE:
+ case OLS:
+ case OGT:
+ case OHI:
+ if(cmp(x, add(lo, -1)) <= 0)
+ goto useless;
+ if(cmp(x, hi) >= 0)
+ goto useless;
+ break;
+ case OEQ:
+ case ONE:
+ /*
+ * Don't warn about comparisons if the expression
+ * is as wide as the value: the compiler-supplied casts
+ * will make both outcomes possible.
+ */
+ if(lt->width >= rt->width && debug['w'] < 2)
+ return 0;
+ if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
+ goto useless;
+ break;
+ }
+ return 0;
+
+useless:
+ if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
+ snprint(xbuf, sizeof xbuf, "%lld", x.b);
+ else if(x.a == 0)
+ snprint(xbuf, sizeof xbuf, "%#llux", x.b);
+ else
+ snprint(xbuf, sizeof xbuf, "%#llx", x.b);
+ if(reverse)
+ snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
+ xbuf, cmps[relindex(n->op)], lt);
+ else
+ snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
+ lt, cmps[relindex(n->op)], xbuf);
+ warn(n, "useless or misleading comparison: %s", cmpbuf);
+ return 0;
+}
+