root/src/cmd/cc/com.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. complex
  2. tcom
  3. tcomo
  4. tcoma
  5. tcomd
  6. tcomx
  7. tlvalue
  8. ccom
  9. cmp
  10. add
  11. big
  12. compar

// 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;
        static TRune zer;

        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[TRUNE]) {
                        o = outstring(0, 0);
                        while(o & 3) {
                                outlstring(&zer, sizeof(TRune));
                                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, (1ULL<<(l->type->width*8))-1);
        }else{
                lo = big(~0ULL, -(1ULL<<(l->type->width*8-1)));
                hi = big(0, (1ULL<<(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;
}


/* [<][>][^][v][top][bottom][index][help] */