URI:
       fold.c - scc - simple c99 compiler
  HTML git clone git://git.simple-cc.org/scc
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
       fold.c (17623B)
       ---
            1 #include <assert.h>
            2 #include <stdlib.h>
            3 
            4 #include <scc/scc.h>
            5 #include "cc1.h"
            6 
            7 
            8 unsigned long long
            9 ones(int nbytes)
           10 {
           11         return (nbytes == 8) ? -1 : ~(-1ull << nbytes * 8);
           12 }
           13 
           14 static int
           15 addi(long long l, long long r, Type *tp)
           16 {
           17         struct limits *lim = getlimits(tp);
           18         long long max = lim->max.i, min = lim->min.i;
           19 
           20         if (l < 0 && r < 0 && l >= min - r ||
           21             l == 0 ||
           22             r == 0 ||
           23             l < 0 && r > 0 ||
           24             l > 0 && r < 0 ||
           25             l > 0 && r > 0 && l <= max - r) {
           26                 return 1;
           27         }
           28         warn("overflow in constant expression");
           29         return 0;
           30 }
           31 
           32 static int
           33 addf(double l, double r, Type *tp)
           34 {
           35         struct limits *lim = getlimits(tp);
           36         double max = lim->max.f, min = lim->min.f;
           37 
           38         if (l < 0 && r < 0 && l >= min - r ||
           39             l == 0 ||
           40             r == 0 ||
           41             l < 0 && r > 0 ||
           42             l > 0 && r < 0 ||
           43             l > 0 && r > 0 && l <= max - r) {
           44                 return 1;
           45         }
           46         warn("overflow in constant expression");
           47         return 0;
           48 }
           49 
           50 static int
           51 subi(long long l, long long r, Type *tp)
           52 {
           53         return addi(l, -r, tp);
           54 }
           55 
           56 static int
           57 subf(double l, double r, Type *tp)
           58 {
           59         return addf(l, -r, tp);
           60 }
           61 
           62 static int
           63 muli(long long l, long long r, Type *tp)
           64 {
           65         struct limits *lim = getlimits(tp);
           66         long long max = lim->max.i, min = lim->min.i;
           67 
           68         if (l > -1 && l <= 1 ||
           69             r > -1 && r <= 1 ||
           70             l < 0 && r < 0 && -l <= max/-r ||
           71             l < 0 && r > 0 &&  l >= min/r  ||
           72             l > 0 && r < 0 &&  r >= min/l  ||
           73             l > 0 && r > 0 &&  l <= max/r) {
           74                         return 1;
           75         }
           76         warn("overflow in constant expression");
           77         return 0;
           78 }
           79 
           80 static int
           81 mulf(double l, double r, Type *tp)
           82 {
           83         struct limits *lim = getlimits(tp);
           84         double max = lim->max.f, min = lim->min.f;
           85 
           86         if (l > -1 && l <= 1 ||
           87             r > -1 && r <= 1 ||
           88             l < 0 && r < 0 && -l <= max/-r ||
           89             l < 0 && r > 0 &&  l >= min/r  ||
           90             l > 0 && r < 0 &&  r >= min/l  ||
           91             l > 0 && r > 0 &&  l <= max/r) {
           92                         return 1;
           93         }
           94         warn("overflow in constant expression");
           95         return 0;
           96 }
           97 
           98 static int
           99 divi(long long l, long long r,  Type *tp)
          100 {
          101         struct limits *lim = getlimits(tp);
          102 
          103         if (r == 0 || l == -lim->min.i && r == -1) {
          104                 warn("overflow in constant expression");
          105                 return 0;
          106         }
          107         return 1;
          108 }
          109 
          110 static int
          111 divf(double l, double r,  Type *tp)
          112 {
          113         struct limits *lim = getlimits(tp);
          114 
          115         if (l < 0) l = -l;
          116         if (r < 0) r = -r;
          117 
          118         if (r == 0.0 || r < 1.0 && l > lim->max.f * r) {
          119                 warn("overflow in constant expression");
          120                 return 0;
          121         }
          122         return 1;
          123 }
          124 
          125 static int
          126 lshi(long long l, long long r, Type *tp)
          127 {
          128         if (r < 0 || r >= tp->size * 8) {
          129                 warn("shifting %d bits is undefined", r);
          130                 return 0;
          131         }
          132         return muli(l, 1 << r, tp);
          133 }
          134 
          135 static int
          136 rshi(long long l, long long r, Type *tp)
          137 {
          138         if (r < 0 || r >= tp->size * 8) {
          139                 warn("shifting %d bits is undefined", r);
          140                 return 0;
          141         }
          142         return 1;
          143 }
          144 
          145 static int
          146 foldint(int op, Symbol *res, long long l, long long r)
          147 {
          148         long long i;
          149         Type *tp = res->type;
          150         int (*validate)(long long, long long, Type *tp);
          151 
          152         switch (op) {
          153         case OADD: validate = addi; break;
          154         case OSUB: validate = subi; break;
          155         case OMUL: validate = muli; break;
          156         case ODIV: validate = divi; break;
          157         case OSHL: validate = lshi; break;
          158         case OSHR: validate = rshi; break;
          159         case OMOD: validate = divi; break;
          160         default:   validate = NULL; break;
          161         }
          162 
          163         if (validate && !(*validate)(l, r, tp))
          164                 return 0;
          165 
          166         switch (op) {
          167         case OADD:  i = l + r;  break;
          168         case OSUB:  i = l - r;  break;
          169         case OMUL:  i = l * r;  break;
          170         case ODIV:  i = l / r;  break;
          171         case OMOD:  i = l % r;  break;
          172         case OSHL:  i = l << r; break;
          173         case OSHR:  i = l >> r; break;
          174         case OBAND: i = l & r;  break;
          175         case OBXOR: i = l ^ r;  break;
          176         case OBOR:  i = l | r;  break;
          177         case OAND:  i = l && r; break;
          178         case OOR:   i = l || r; break;
          179         case OLT:   i = l < r;  break;
          180         case OGT:   i = l > r;  break;
          181         case OGE:   i = l >= r; break;
          182         case OLE:   i = l <= r; break;
          183         case OEQ:   i = l == r; break;
          184         case ONE:   i = l != r; break;
          185         case ONEG:  i = !l;     break;
          186         case OSNEG: i = -l;     break;
          187         case OCPL:  i = ~l;     break;
          188         default:    return 0;
          189         }
          190         res->u.i = i;
          191 
          192         DBG("FOLD i l=%lld %d r=%lld = %lld", l, op, r, i);
          193         return 1;
          194 }
          195 
          196 static int
          197 folduint(int op, Symbol *res, unsigned long long l, unsigned long long r)
          198 {
          199         long long i;
          200         unsigned long long u;
          201 
          202         switch (op) {
          203         case OADD:  u = l + r;  break;
          204         case OSUB:  u = l - r;  break;
          205         case OMUL:  u = l * r;  break;
          206         case ODIV:  u = l / r;  break;
          207         case OMOD:  u = l % r;  break;
          208         case OSHL:  u = l << r; break;
          209         case OSHR:  u = l >> r; break;
          210         case OBAND: u = l & r;  break;
          211         case OBXOR: u = l ^ r;  break;
          212         case OBOR:  u = l | r;  break;
          213         case ONEG:  u = !l;     break;
          214         case OSNEG: u = -l;     break;
          215         case OCPL:  u = ~l;     break;
          216         case OAND:  i = l && r; goto sign;
          217         case OOR:   i = l || r; goto sign;
          218         case OLT:   i = l < r;  goto sign;
          219         case OGT:   i = l > r;  goto sign;
          220         case OGE:   i = l >= r; goto sign;
          221         case OLE:   i = l <= r; goto sign;
          222         case OEQ:   i = l == r; goto sign;
          223         case ONE:   i = l != r; goto sign;
          224         default:    return 0;
          225         }
          226         res->u.u = u & ones(res->type->size);
          227 
          228         DBG("FOLD ui l=%llu %d r=%llu = %llu", l, op, r, u);
          229         return 1;
          230 
          231 sign:
          232         res->u.i = i;
          233 
          234         DBG("FOLD sui %llu %d %llu = %llu", l, op, r, i);
          235         return 1;
          236 }
          237 
          238 static int
          239 foldldouble(int op, Symbol *res, long double l, long double r)
          240 {
          241         long double f;
          242         long long i;
          243         int (*validate)(double, double, Type *tp);
          244 
          245         switch (op) {
          246         case OADD: validate = addf; break;
          247         case OSUB: validate = subf; break;
          248         case OMUL: validate = mulf; break;
          249         case ODIV: validate = divf; break;
          250         default:   validate = NULL; break;
          251         }
          252 
          253         if (validate && !(*validate)(l, r, res->type))
          254                 return 0;
          255 
          256         switch (op) {
          257         case OADD: f = l + r;  break;
          258         case OSUB: f = l - r;  break;
          259         case OMUL: f = l * r;  break;
          260         case ODIV: f = l / r;  break;
          261         case OSNEG: f = -l;    break;
          262         case OLT:  i = l < r;  goto comparison;
          263         case OGT:  i = l > r;  goto comparison;
          264         case OGE:  i = l >= r; goto comparison;
          265         case OLE:  i = l <= r; goto comparison;
          266         case OEQ:  i = l == r; goto comparison;
          267         case ONE:  i = l != r; goto comparison;
          268         default:   return 0;
          269         }
          270         res->u.ld = f;
          271 
          272         DBG("FOLD f l=%llf %d r=%llf = %llf", l, op, r, f);
          273         return 1;
          274 
          275 comparison:
          276         res->u.i = i;
          277 
          278         DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
          279         return 1;
          280 }
          281 
          282 static int
          283 folddouble(int op, Symbol *res, double l, double r)
          284 {
          285         double f;
          286         long long i;
          287         int (*validate)(double, double, Type *tp);
          288 
          289         switch (op) {
          290         case OADD: validate = addf; break;
          291         case OSUB: validate = subf; break;
          292         case OMUL: validate = mulf; break;
          293         case ODIV: validate = divf; break;
          294         default:   validate = NULL; break;
          295         }
          296 
          297         if (validate && !(*validate)(l, r, res->type))
          298                 return 0;
          299 
          300         switch (op) {
          301         case OADD: f = l + r;  break;
          302         case OSUB: f = l - r;  break;
          303         case OMUL: f = l * r;  break;
          304         case ODIV: f = l / r;  break;
          305         case OSNEG: f = -l;    break;
          306         case OLT:  i = l < r;  goto comparison;
          307         case OGT:  i = l > r;  goto comparison;
          308         case OGE:  i = l >= r; goto comparison;
          309         case OLE:  i = l <= r; goto comparison;
          310         case OEQ:  i = l == r; goto comparison;
          311         case ONE:  i = l != r; goto comparison;
          312         default:   return 0;
          313         }
          314         res->u.d = f;
          315 
          316         DBG("FOLD f l=%lf %d r=%lf = %lf", l, op, r, f);
          317         return 1;
          318 
          319 comparison:
          320         res->u.i = i;
          321 
          322         DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
          323         return 1;
          324 }
          325 
          326 static int
          327 foldfloat(int op, Symbol *res, float l, float r)
          328 {
          329         float f;
          330         long long i;
          331         int (*validate)(double, double, Type *tp);
          332 
          333         switch (op) {
          334         case OADD: validate = addf; break;
          335         case OSUB: validate = subf; break;
          336         case OMUL: validate = mulf; break;
          337         case ODIV: validate = divf; break;
          338         default:   validate = NULL; break;
          339         }
          340 
          341         if (validate && !(*validate)(l, r, res->type))
          342                 return 0;
          343 
          344         switch (op) {
          345         case OADD: f = l + r;  break;
          346         case OSUB: f = l - r;  break;
          347         case OMUL: f = l * r;  break;
          348         case ODIV: f = l / r;  break;
          349         case OSNEG: f = -l;    break;
          350         case OLT:  i = l < r;  goto comparison;
          351         case OGT:  i = l > r;  goto comparison;
          352         case OGE:  i = l >= r; goto comparison;
          353         case OLE:  i = l <= r; goto comparison;
          354         case OEQ:  i = l == r; goto comparison;
          355         case ONE:  i = l != r; goto comparison;
          356         default:   return 0;
          357         }
          358         res->u.f = f;
          359 
          360         DBG("FOLD f l=%f %d r=%f = %f", l, op, r, f);
          361         return 1;
          362 
          363 comparison:
          364         res->u.i = i;
          365 
          366         DBG("FOLD if l=%lf %d r=%lf = %lld", l, op, r, i);
          367         return 1;
          368 }
          369 
          370 
          371 static Node *
          372 foldconst(int type, int op, Type *tp, Symbol *ls, Symbol *rs)
          373 {
          374         Symbol *sym, aux;
          375         long long i;
          376         unsigned long long u;
          377         float f;
          378         double d;
          379         long double ld;
          380 
          381         aux.type = tp;
          382         switch (type) {
          383         case INT:
          384                 i = (rs) ? rs->u.i : 0;
          385                 if (!foldint(op, &aux, ls->u.i, i))
          386                         return NULL;
          387                 break;
          388         case PTR:
          389         case UNSIGNED:
          390                 u = (rs) ? rs->u.u : 0u;
          391                 if (!folduint(op, &aux, ls->u.u, u))
          392                         return NULL;
          393                 break;
          394         case FLOAT:
          395                 if (tp == floattype) {
          396                         f = (rs) ? rs->u.f : 0.0;
          397                         if (!foldfloat(op, &aux, ls->u.f, f))
          398                                 return NULL;
          399                 } else if (tp == doubletype) {
          400                         d = (rs) ? rs->u.d : 0.0;
          401                         if (!folddouble(op, &aux, ls->u.d, d))
          402                                 return NULL;
          403                 } else {
          404                         ld = (rs) ? rs->u.ld : 0.0;
          405                         if (!foldldouble(op, &aux, ls->u.ld, ld))
          406                                 return NULL;
          407                 }
          408                 break;
          409         default:
          410                 abort();
          411         }
          412         sym = newsym(NS_IDEN, NULL);
          413         sym->flags |= SCONSTANT;
          414         sym->type = tp;
          415         sym->u = aux.u;
          416         return constnode(sym);
          417 }
          418 
          419 static Node *
          420 foldcast(Node *np, Node *l)
          421 {
          422         long double ld;
          423         unsigned long long negmask, mask, u;
          424         Type *newtp = np->type, *oldtp = l->type;
          425         Symbol aux, *sym, *osym = l->sym;
          426 
          427         if ((l->flags & NCONST) == 0 || !osym)
          428                 return np;
          429 
          430         switch (newtp->op) {
          431         case PTR:
          432         case INT:
          433         case ENUM:
          434                 switch (oldtp->op) {
          435                 case PTR:
          436                 case INT:
          437                 case ENUM:
          438                         u = (oldtp->prop & TSIGNED) ? osym->u.i : osym->u.u;
          439                         break;
          440                 case FLOAT:
          441                         oldtp = newtp;
          442                         u = osym->u.f;
          443                         break;
          444                 default:
          445                         return  np;
          446                 }
          447                 mask = ones(newtp->size);
          448                 if (newtp->prop & TSIGNED) {
          449                         negmask = ~mask;
          450                         if (u & (negmask >> 1) & mask)
          451                                 u |= negmask;
          452                         aux.u.i = u;
          453                 } else {
          454                         aux.u.u = u & mask;
          455                 }
          456                 break;
          457         case FLOAT:
          458                 if (oldtp->op != FLOAT) {
          459                         if (oldtp->prop & TSIGNED)
          460                                 ld = osym->u.i;
          461                         else
          462                                 ld = osym->u.u;
          463                 } else if (oldtp == floattype) {
          464                         ld = osym->u.f;
          465                 } else if (oldtp == doubletype) {
          466                         ld = osym->u.d;
          467                 } else if (oldtp == ldoubletype) {
          468                         ld = osym->u.ld;
          469                 } else {
          470                         return np;
          471                 }
          472 
          473                 if (newtp == floattype)
          474                         aux.u.f = ld;
          475                 else if (newtp == doubletype)
          476                         aux.u.d = ld;
          477                 else if (newtp == ldoubletype)
          478                         aux.u.ld = ld;
          479                 else
          480                         abort();
          481                 break;
          482         default:
          483                 return np;
          484         }
          485 
          486         DBG("FOLD cast %c->%c", oldtp->letter, newtp->letter);
          487         freetree(np);
          488         sym = newsym(NS_IDEN, NULL);
          489         sym->flags |= SCONSTANT;
          490         sym->type = newtp;
          491         sym->u = aux.u;
          492         return constnode(sym);
          493 }
          494 
          495 static Node *
          496 foldunary(Node *np)
          497 {
          498         Node *l = np->left;
          499         Node *aux;
          500         Symbol *sym;
          501         int op = l->op;
          502 
          503         switch (np->op) {
          504         case ONEG:
          505                 if (l->op == ONEG)
          506                         break;
          507                 return np;
          508         case OADD:
          509                 DBG("FOLD unary delete %d", np->op);
          510                 np->left = NULL;
          511                 freetree(np);
          512                 return l;
          513         case OCAST:
          514                 return foldcast(np, l);
          515         case OSNEG:
          516         case OCPL:
          517                 if (op != np->op)
          518                         return np;
          519                 break;
          520         case OPTR:
          521                 if (op != OADDR || np->type != l->left->type)
          522                         return np;
          523                 break;
          524         case OADDR:
          525                 /* &(*s).f -> s + offsetof(typeof(*s), f) */
          526                 if (op == OFIELD && l->left->op == OPTR) {
          527                         DBG("FOLD collapse '&(*s).f' %d", np->op);
          528                         aux = node(OADD,
          529                                    np->type,
          530                                    l->left->left,
          531                                    offsetnode(l->right->sym, np->type));
          532 
          533                         if (aux->left->flags & NCONST)
          534                                 aux->flags |= NCONST;
          535                         l->left->left = NULL;
          536                         freetree(np);
          537                         return aux;
          538                 }
          539 
          540                 /* &s.f -> &s + offsetof(typeof(s), f) */
          541                 if (op == OFIELD) {
          542                         DBG("FOLD collapse '&s.f' %d", np->op);
          543                         aux = node(OADD,
          544                                    np->type,
          545                                    node(OADDR, np->type, l->left, NULL),
          546                                    offsetnode(l->right->sym, np->type));
          547 
          548                         if (np->flags & NCONST)
          549                                 aux->flags |= NCONST;
          550                         l->left = NULL;
          551                         freetree(np);
          552                         return aux;
          553                 }
          554 
          555                 if (op != OPTR)
          556                         return np;
          557                 break;
          558         default:
          559                 return np;
          560         }
          561         DBG("FOLD unary cancel %d", np->op);
          562         aux = l->left;
          563         l->left = NULL;
          564         freetree(np);
          565         return aux;
          566 }
          567 
          568 static Node *
          569 fold(Node *np)
          570 {
          571         Symbol *rs, *ls;
          572         Type *optype;
          573         int type;
          574         int op = np->op;
          575         Node *p, *lp = np->left, *rp = np->right;
          576         Type *tp = np->type;
          577 
          578         if (!lp && !rp)
          579                 return np;
          580 
          581         if ((op == ODIV || op == OMOD) && cmpnode(rp, 0)) {
          582                 warn("division by 0");
          583                 return np;
          584         }
          585         /*
          586          * Return if any of the children is no constant,
          587          * or it is a constant generated when
          588          * the address of a static variable is taken
          589          * (when we don't know the physical address so
          590          * we cannot fold it)
          591          */
          592         if (!rp) {
          593                 rs = NULL;
          594         } else {
          595                 if (!(rp->flags & NCONST) || !rp->sym)
          596                         return np;
          597                 rs = rp->sym;
          598         }
          599 
          600         if ((lp->flags & NCONST) == 0 || !lp->sym)
          601                 return np;
          602         optype = lp->type;
          603         ls = lp->sym;
          604 
          605         type = optype->op;
          606         switch (type) {
          607         case ENUM:
          608         case INT:
          609                 if (!(optype->prop & TSIGNED))
          610                         type = UNSIGNED;
          611         case PTR:
          612         case FLOAT:
          613                 if ((p = foldconst(type, op, tp, ls, rs)) == NULL) {
          614                         np->flags &= ~NCONST;
          615                         return np;
          616                 }
          617                 freetree(np);
          618                 return p;
          619         default:
          620                 return np;
          621         }
          622 }
          623 
          624 static void
          625 commutative(Node *np)
          626 {
          627         int op = np->op;
          628         Node *l = np->left, *r = np->right;
          629 
          630         if (r == NULL || r->flags&NCONST || !(l->flags&NCONST))
          631                 return;
          632 
          633         switch (op) {
          634         case OLT:
          635         case OGT:
          636         case OGE:
          637         case OLE:
          638                 DBG("FOLD neg commutative %d", np->op);
          639                 np->op = negop(op);
          640         case OEQ:
          641         case ONE:
          642         case OADD:
          643         case OMUL:
          644         case OBAND:
          645         case OBXOR:
          646         case OBOR:
          647                 DBG("FOLD commutative %d", np->op);
          648                 np->left = r;
          649                 np->right = l;
          650                 break;
          651         }
          652 }
          653 
          654 static Node *
          655 identity(Node *np)
          656 {
          657         int iszeror, isoner;
          658         int iszerol, isonel;
          659         Node *lp = np->left, *rp = np->right;
          660 
          661         if (!rp)
          662                 return np;
          663 
          664         iszeror = cmpnode(rp, 0);
          665         isoner = cmpnode(rp, 1),
          666         iszerol = cmpnode(lp, 0);
          667         isonel = cmpnode(lp, 1);
          668 
          669         switch (np->op) {
          670         case OOR:
          671                 /*
          672                  * 1 || i => 1    (free right)
          673                  * i || 0 => i    (free right)
          674                  * 0 || i => i    (free left)
          675                  * i || 1 => i,1  (comma)
          676                  */
          677                 if (isonel | iszeror)
          678                         goto free_right;
          679                 if (iszerol)
          680                         goto free_left;
          681                 if (isoner)
          682                         goto change_to_comma;
          683                 return np;
          684         case OAND:
          685                 /*
          686                  * 0 && i => 0    (free right)
          687                  * i && 1 => i    (free right)
          688                  * 1 && i => i    (free left)
          689                  * i && 0 => i,0  (comma)
          690                  */
          691                 if (iszerol | isoner)
          692                         goto free_right;
          693                 if (isonel)
          694                         goto free_left;
          695                 if (iszeror)
          696                         goto change_to_comma;
          697                 return np;
          698         case OSHL:
          699         case OSHR:
          700                 /*
          701                  * i >> 0 => i    (free right)
          702                  * i << 0 => i    (free right)
          703                  * 0 >> i => 0    (free right)
          704                  * 0 << i => 0    (free right)
          705                  */
          706                 if (iszeror | iszerol)
          707                         goto free_right;
          708                 return np;
          709         case OBXOR:
          710         case OADD:
          711         case OBOR:
          712         case OSUB:
          713                 /*
          714                  * i + 0  => i
          715                  * i - 0  => i
          716                  * i | 0  => i
          717                  * i ^ 0  => i
          718                  */
          719                 if (iszeror)
          720                         goto free_right;
          721                 return np;
          722         case OMUL:
          723                 /*
          724                  * i * 0  => i,0 (comma)
          725                  * i * 1  => i   (free right)
          726                  */
          727                 if (iszeror)
          728                         goto change_to_comma;
          729                 if (isoner)
          730                         goto free_right;
          731                 return np;
          732         case ODIV:
          733                 /* i / 1  => i */
          734                 if (isoner)
          735                         goto free_right;
          736                 return np;
          737         case OBAND:
          738                 /* i & ~0 => i */
          739                 if (cmpnode(rp, -1))
          740                         goto free_right;
          741                 return np;
          742         case OMOD:
          743                 /* i % 1  => i,1 */
          744                 if (isoner)
          745                         goto change_to_comma;
          746         default:
          747                 return np;
          748         }
          749 
          750 free_right:
          751         DBG("FOLD identity %d", np->op);
          752         np->left = NULL;
          753         freetree(np);
          754         return lp;
          755 
          756 free_left:
          757         DBG("FOLD identity %d", np->op);
          758         np->right = NULL;
          759         freetree(np);
          760         return rp;
          761 
          762 change_to_comma:
          763         DBG("FOLD identity %d", np->op);
          764         np->op = OCOMMA;
          765         return np;
          766 }
          767 
          768 static Node *
          769 foldternary(Node *np)
          770 {
          771         Node *cond = np->left, *body = np->right;
          772 
          773         if ((cond->flags & NCONST) == 0)
          774                 return np;
          775         if (cmpnode(cond, 0)) {
          776                 np = body->right;
          777                 freetree(body->left);
          778         } else {
          779                 np = body->left;
          780                 freetree(body->right);
          781         }
          782 
          783         DBG("FOLD ternary");
          784         body->left = NULL;
          785         body->right = NULL;
          786         freetree(cond);
          787         free(body);
          788         return np;
          789 }
          790 
          791 static Node *xsimplify(Node *);
          792 
          793 static void
          794 reduce(Node *np)
          795 {
          796         Node *lp = np->left, *rp = np->right;
          797         Node *aux, *aux2;
          798         int log, op = np->op;
          799 
          800         if (np->type->prop & TSIGNED)
          801                 return;
          802         if (!power2node(rp, &log))
          803                 return;
          804 
          805         switch (op) {
          806         case OMUL:
          807                 /* i * 2^n => i << n */
          808                 np->op = OSHL;
          809                 rp->sym->u.u = log;
          810                 break;
          811         case ODIV:
          812                 /* i / 2^n => i >> n */
          813                 np->op = OSHR;
          814                 rp->sym->u.u = log;
          815                 break;
          816         case OMOD:
          817                 /* i % 2^n => i & n-1 */
          818                 np->op = OBAND;
          819                 rp->sym->u.u--;
          820                 break;
          821         default:
          822                 return;
          823         }
          824 
          825         DBG("FOLD reduce %d->%d", op, np->op);
          826 }
          827 
          828 static void
          829 associative(Node *np)
          830 {
          831         Node *l = np->left, *r = np->right;
          832 
          833         switch (np->op) {
          834         case OADD:
          835         case OMUL:
          836         case OBAND:
          837         case OBXOR:
          838         case OBOR:
          839                 if (np->op != l->op
          840                 || l->right->op != OSYM
          841                 || !(l->right->sym->flags&SCONSTANT)) {
          842                         return;
          843                 }
          844 
          845                 DBG("FOLD associative %d", np->op);
          846                 np->left = l->left;
          847                 l->left = r;
          848                 np->right = fold(l);
          849                 break;
          850         }
          851 }
          852 
          853 /* TODO: fold OCOMMA */
          854 static Node *
          855 xxsimplify(Node *np)
          856 {
          857         int op;
          858         int isfloat = np->type->op == FLOAT;
          859 
          860         np->left = xsimplify(np->left);
          861         np->right = xsimplify(np->right);
          862 
          863 repeat:
          864         switch (op = np->op) {
          865         case OASK:
          866                 np = foldternary(np);
          867                 break;
          868         case OCALL:
          869         case OPAR:
          870         case OSYM:
          871         case OASSIGN:
          872         case OA_MUL:
          873         case OA_DIV:
          874         case OA_MOD:
          875         case OA_ADD:
          876         case OA_SUB:
          877         case OA_SHL:
          878         case OA_SHR:
          879         case OA_AND:
          880         case OA_XOR:
          881         case OA_OR:
          882                 break;
          883         case OSNEG:
          884         case OCPL:
          885         case OADDR:
          886         case OPTR:
          887         case INC:
          888         case DEC:
          889         case OCAST:
          890         case ONEG:
          891                 assert(!np->right);
          892                 np = foldunary(np);
          893                 np = fold(np);
          894                 break;
          895         default:
          896                 if (!isfloat) {
          897                         commutative(np);
          898                         associative(np);
          899                 }
          900                 np = fold(np);
          901                 if (!isfloat) {
          902                         np = identity(np);
          903                         reduce(np);
          904                 }
          905                 break;
          906         }
          907 
          908         if (op != np->op)
          909                 goto repeat;
          910         return np;
          911 }
          912 
          913 static Node *
          914 xsimplify(Node *np)
          915 {
          916         if (!np)
          917                 return NULL;
          918 
          919         if (enadebug)
          920                 prtree("simplify before", np);
          921         np = xxsimplify(np);
          922         if (enadebug)
          923                 prtree("simplify after", np);
          924 
          925         return np;
          926 }
          927 
          928 Node *
          929 simplify(Node *np)
          930 {
          931         DBG("SIMPLIFY");
          932         return xsimplify(np);
          933         DBG("SIMPLIFY DONE");
          934 }