| // 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 "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) | |
| warn(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; | |
| } | |