Node *fold(Node *n, int foldvar) { Node **args, *r; Type *t; vlong a, b; size_t i; if (!n) return NULL; if (n->type != Nexpr) return n; r = NULL; args = n->expr.args; for (i = 0; i < n->expr.nargs; i++) args[i] = fold(args[i], foldvar); switch (exprop(n)) { case Ovar: if (foldvar && issmallconst(decls[n->expr.did])) r = fold(decls[n->expr.did]->decl.init, foldvar); break; case Oadd: /* x + 0 = 0 */ if (isval(args[0], 0)) r = args[1]; if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a + b, exprtype(n)); break; case Osub: /* x - 0 = 0 */ if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a - b, exprtype(n)); break; case Omul: /* 1 * x = x */ if (isval(args[0], 1)) r = args[1]; if (isval(args[1], 1)) r = args[0]; /* 0 * x = 0 */ if (isval(args[0], 0)) r = args[0]; if (isval(args[1], 0)) r = args[1]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a * b, exprtype(n)); break; case Odiv: /* x/1 = x */ if (isval(args[1], 1)) r = args[0]; /* 0/x = 0 */ if (isval(args[1], 0)) r = args[1]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a / b, exprtype(n)); break; case Omod: /* x%1 = x */ if (isval(args[1], 0)) r = args[0]; if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a % b, exprtype(n)); break; case Oneg: if (islit(args[0], &a)) r = val(n->line, -a, exprtype(n)); break; case Obsl: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a << b, exprtype(n)); break; case Obsr: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a >> b, exprtype(n)); break; case Obor: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a | b, exprtype(n)); break; case Oband: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a & b, exprtype(n)); break; case Obxor: if (islit(args[0], &a) && islit(args[1], &b)) r = val(n->line, a ^ b, exprtype(n)); break; case Omemb: t = tybase(exprtype(args[0])); /* we only fold lengths right now */ if (t->type == Tyarray && !strcmp(namestr(args[1]), "len")) r = t->asize; break; case Ocast: r = foldcast(n); break; default: break; } if (r) return r; else return n; }
Node *fold(Node *n, int foldvar) { Node **args, *r; Type *t; vlong a, b; size_t i; if (!n) return NULL; if (n->type != Nexpr) return n; r = NULL; args = n->expr.args; if (n->expr.idx) n->expr.idx = fold(n->expr.idx, foldvar); for (i = 0; i < n->expr.nargs; i++) args[i] = fold(args[i], foldvar); switch (exprop(n)) { case Ovar: if (foldvar && issmallconst(decls[n->expr.did])) r = fold(decls[n->expr.did]->decl.init, foldvar); break; case Oadd: /* x + 0 = 0 */ if (isintval(args[0], 0)) r = args[1]; if (isintval(args[1], 0)) r = args[0]; if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a + b, exprtype(n)); break; case Osub: /* x - 0 = 0 */ if (isintval(args[1], 0)) r = args[0]; if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a - b, exprtype(n)); break; case Omul: /* 1 * x = x */ if (isintval(args[0], 1)) r = args[1]; if (isintval(args[1], 1)) r = args[0]; /* 0 * x = 0 */ if (isintval(args[0], 0)) r = args[0]; if (isintval(args[1], 0)) r = args[1]; if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a * b, exprtype(n)); break; case Odiv: /* x/0 = error */ if (isintval(args[1], 0)) fatal(args[1], "division by zero"); /* x/1 = x */ if (isintval(args[1], 1)) r = args[0]; /* 0/x = 0 */ if (isintval(args[1], 0)) r = args[1]; if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a / b, exprtype(n)); break; case Omod: /* x%0 = error */ if (isintval(args[1], 0)) fatal(args[1], "division by zero"); /* x%1 = 0 */ if (isintval(args[1], 1)) r = val(n->loc, 0, exprtype(n)); if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a % b, exprtype(n)); break; case Oneg: if (getintlit(args[0], &a)) r = val(n->loc, -a, exprtype(n)); break; case Obsl: if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a << b, exprtype(n)); break; case Obsr: if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a >> b, exprtype(n)); break; case Obor: if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a | b, exprtype(n)); break; case Oband: if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a & b, exprtype(n)); break; case Obxor: if (getintlit(args[0], &a) && getintlit(args[1], &b)) r = val(n->loc, a ^ b, exprtype(n)); break; case Omemb: t = tybase(exprtype(args[0])); /* we only fold lengths right now */ if (t->type == Tyarray && !strcmp(namestr(args[1]), "len")) { r = t->asize; r->expr.type = exprtype(n); } break; case Oarr: if (n->expr.nargs > 0) qsort(n->expr.args, n->expr.nargs, sizeof(Node*), idxcmp); break; case Ocast: r = foldcast(n); break; default: break; } if (r && n->expr.idx) r->expr.idx = n->expr.idx; if (r) return r; else return n; }