Example #1
0
File: fold.c Project: 8l/mc
static Node *foldcast(Node *n)
{
	Type *to, *from;
	Node *sub;

	sub = n->expr.args[0];
	to = exprtype(n);
	from = exprtype(sub);

	switch (tybase(to)->type) {
	case Tybool:
	case Tyint8: case Tyint16: case Tyint32: case Tyint64:
	case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
	case Tyint: case Tyuint: case Tychar: case Tybyte:
	case Typtr:
		switch (tybase(from)->type) {
		case Tybool:
		case Tyint8: case Tyint16: case Tyint32: case Tyint64:
		case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
		case Tyint: case Tyuint: case Tychar: case Tybyte:
		case Typtr:
			if (exprop(sub) == Olit || tybase(from)->type == tybase(to)->type) {
				sub->expr.type = to;
				return sub;
			} else {
				return n;
			}
		default:
			return n;
		}
	default:
		return n;
	}
	return n;
}
Example #2
0
/* Simplifies taking a slice of an array, pointer,
 * or other slice down to primitive pointer operations */
static Node *simpslice(Simp *s, Node *n, Node *dst)
{
    Node *t;
    Node *start, *end;
    Node *base, *sz, *len;
    Node *stbase, *stlen;

    if (dst)
        t = dst;
    else
        t = temp(s, n);
    /* *(&slice) = (void*)base + off*sz */
    base = slicebase(s, n->expr.args[0], n->expr.args[1]);
    start = ptrsized(s, rval(s, n->expr.args[1], NULL));
    end = ptrsized(s, rval(s, n->expr.args[2], NULL));
    len = sub(end, start);
    /* we can be storing through a pointer, in the case
     * of '*foo = bar'. */
    if (tybase(exprtype(t))->type == Typtr) {
        stbase = set(simpcast(s, t, mktyptr(t->line, tyintptr)), base);
        sz = addk(simpcast(s, t, mktyptr(t->line, tyintptr)), Ptrsz);
    } else {
        stbase = set(deref(addr(s, t, tyintptr)), base);
        sz = addk(addr(s, t, tyintptr), Ptrsz);
    }
    /* *(&slice + ptrsz) = len */
    stlen = set(deref(sz), len);
    append(s, stbase);
    append(s, stlen);
    return t;
}
Example #3
0
File: flatten.c Project: oridb/mc
static Node *
comparecomplex(Flattenctx *s, Node *n, Op op)
{
	Type *ty;
	Node *l, *r, *e;

	/* special case: unions with nullary constructors can be compared easily. */
	ty = tybase(exprtype(n->expr.args[0]));
	if (ty->type == Tyunion && isenum(ty)) {
		l = mkexpr(n->loc, Outag, rval(s, n->expr.args[0]), NULL);
		r = mkexpr(n->loc, Outag, rval(s, n->expr.args[1]), NULL);
		l->expr.type = mktype(n->loc, Tyuint32);
		r->expr.type = mktype(n->loc, Tyuint32);
		if (op == Oeq)
			e = mkexpr(n->loc, Oueq, l, r, NULL);
		else if (op == One)
			e = mkexpr(n->loc, Oune, l, r, NULL);
		else
			fatal(n, "unsupported operator %s for enum union", opstr[op]);
		e->expr.type = mktype(n->loc, Tybool);
		return e;
	}
	fatal(n, "cannot compare values of type %s for equality\n",
	    tystr(exprtype(n->expr.args[0])));
	return NULL;
}
Example #4
0
static Node *slicebase(Simp *s, Node *n, Node *off)
{
    Node *t, *u, *v;
    Type *ty;
    int sz;

    t = rval(s, n, NULL);
    u = NULL;
    ty = tybase(exprtype(n));
    switch (ty->type) {
        case Typtr:     u = t; break;
        case Tyarray:   u = addr(s, t, base(exprtype(n))); break;
        case Tyslice:   u = load(addr(s, t, mktyptr(n->line, base(exprtype(n))))); break;
        default: die("Unslicable type %s", tystr(n->expr.type));
    }
    /* safe: all types we allow here have a sub[0] that we want to grab */
    if (off) {
      off = ptrsized(s, rval(s, off, NULL));
      sz = tysize(n->expr.type->sub[0]);
      v = mul(off, disp(n->line, sz));
      return add(u, v);
    } else {
      return u;
    }
}
Example #5
0
File: match.c Project: 8l/myrddin
static Node *arrayelt(Node *n, size_t i)
{
    Node *idx, *elt;

    idx = mkintlit(n->loc, i);
    idx->expr.type = mktype(n->loc, Tyuint64);
    elt = mkexpr(n->loc, Oidx, n, idx, NULL);
    elt->expr.type = tybase(exprtype(n))->sub[0];
    return elt;
}
Example #6
0
File: flatten.c Project: oridb/mc
static Node *
asn(Node *a, Node *b)
{
	Node *n;

	assert(a != NULL && b != NULL);
	if (tybase(exprtype(a))->type == Tyvoid)
		return a;

	n = mkexpr(a->loc, Oasn, a, b, NULL);
	n->expr.type = exprtype(a);
	return n;
}
Example #7
0
static int issmallconst(Node *dcl)
{
    Type *t;

    if (!dcl->decl.isconst)
        return 0;
    if (!dcl->decl.init)
        return 0;
    t = tybase(exprtype(dcl->decl.init));
    if (t->type <= Tyfloat64)
        return 1;
    return 0;
}
Example #8
0
/* gets the byte offset of 'memb' within the aggregate type 'aggr' */
static size_t offset(Node *aggr, Node *memb)
{
    Type *ty;
    Node **nl;
    size_t i;
    size_t off;

    ty = tybase(exprtype(aggr));
    if (ty->type == Typtr)
        ty = tybase(ty->sub[0]);

    assert(ty->type == Tystruct);
    nl = ty->sdecls;
    off = 0;
    for (i = 0; i < ty->nmemb; i++) {
        off = tyalign(off, size(nl[i]));
        if (!strcmp(namestr(memb), declname(nl[i])))
            return off;
        off += size(nl[i]);
    }
    die("Could not find member %s in struct", namestr(memb));
    return -1;
}
Example #9
0
File: match.c Project: 8l/myrddin
static int isexhaustive(Dtree *dt)
{
    Type *subt;
    size_t i;

    if (dt->any)
        return 1;

    if (dt->nsub > 0) {
        subt = tybase(exprtype(dt->sub[0]->patexpr));
        if (dt->nsub != nconstructors(subt))
            return 0;
    }
    switch (exprop(dt->patexpr)) {
        case Ovar:
            return 1;
        case Olit:
            return 1;
        case Oucon:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Otup:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Oarr:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        case Ostruct:
            for (i = 0; i < dt->nsub; i++)
                if (!isexhaustive(dt->sub[i]))
                    return 0;
            return 1;
            break;
        default:
            die("Invalid pattern in exhaustivenes check. BUG.");
            break;
    }
    return 0;
}
Example #10
0
static Node *simpucon(Simp *s, Node *n, Node *dst)
{
    Node *tmp, *u, *tag, *elt, *sz;
    Node *r;
    Type *ty;
    Ucon *uc;
    size_t i;

    /* find the ucon we're constructing here */
    ty = tybase(n->expr.type);
    uc = NULL;
    for (i = 0; i < ty->nmemb; i++) {
        if (!strcmp(namestr(n->expr.args[0]), namestr(ty->udecls[i]->name))) {
            uc = ty->udecls[i];
            break;
        }
    }
    if (!uc)
        die("Couldn't find union constructor");

    if (dst)
        tmp = dst;
    else
        tmp = temp(s, n);

    /* Set the tag on the ucon */
    u = addr(s, tmp, mktype(n->line, Tyuint));
    tag = mkintlit(n->line, uc->id);
    tag->expr.type = mktype(n->line, Tyuint);
    append(s, set(deref(u), tag));


    /* fill the value, if needed */
    if (!uc->etype)
        return tmp;
    elt = rval(s, n->expr.args[1], NULL);
    u = addk(u, Wordsz);
    if (stacktype(uc->etype)) {
        elt = addr(s, elt, uc->etype);
        sz = disp(n->line, tysize(uc->etype));
        r = mkexpr(n->line, Oblit, u, elt, sz, NULL);
    } else {
        r = set(deref(u), elt);
    }
    append(s, r);
    return tmp;
}
Example #11
0
static void checkundef(Node *n, Reaching *r, Bitset *reach, Bitset *kill)
{
    size_t i, j, did;
    Node *def;
    Type *t;

    if (n->type != Nexpr)
        return;
    if (exprop(n) == Ovar) {
        did = n->expr.did;
        for (j = 0; j < r->ndefs[did]; j++) {
            t = tybase(exprtype(n));
            if (t->type == Tystruct || t->type == Tyunion || t->type == Tyarray || t->type == Tytuple)
                continue;
            if (bshas(kill, r->defs[did][j]))
                continue;
            if (!bshas(reach, r->defs[did][j]))
                continue;
            def = nodes[r->defs[did][j]];
            if (exprop(def) == Oundef)
                fatal(n, "%s used before definition", namestr(n->expr.args[0]));
        }
    } else {
        switch (exprop(n)) {
            case Oset:
            case Oasn:
            case Oblit:
                checkundef(n->expr.args[1], r, reach, kill);
                break;
            case Oaddr:
            case Oslice:
                /* these don't actually look at the of args[0], so they're ok. */
                for (i = 1; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
            case Ocall:
                for (i = 1; i < n->expr.nargs; i++)
                    if (exprop(n->expr.args[i]) != Oaddr)
                        checkundef(n->expr.args[i], r, reach, kill);
                break;
            default:
                for (i = 0; i < n->expr.nargs; i++)
                    checkundef(n->expr.args[i], r, reach, kill);
                break;
        }
    }
}
Example #12
0
File: match.c Project: 8l/myrddin
/* We treat all integer types, boolean types, etc, as having 2^n constructors.
 *
 * since, of course, we can't represent all of the constructors for 64 bit
 * integers using 64 bit values, we just approximate it. We'd have failed (run
 * out of memory, etc) long before getting to this code if we actually had that
 * many branches of the switch statements anyways.
 */
static size_t nconstructors(Type *t)
{
    if (!t)
        return 0;

    t = tybase(t);
    switch (t->type) {
        case Tyvoid:    return 0;               break;
        case Tybool:    return 2;               break;
        case Tychar:    return 0x10ffff;        break;

        /* signed ints */
        case Tyint8:    return 0x100;           break;
        case Tyint16:   return 0x10000;         break;
        case Tyint32:   return 0x100000000;     break;
        case Tyint:     return 0x100000000;     break;
        case Tyint64:   return ~0ull;           break;

        /* unsigned ints */
        case Tybyte:    return 0x100;           break;
        case Tyuint8:   return 0x100;           break;
        case Tyuint16:  return 0x10000;         break;
        case Tyuint32:  return 0x100000000;     break;
        case Tyuint:    return 0x100000000;     break;
        case Tyuint64:  return ~0ull;           break;

        /* floats */
        case Tyflt32:   return ~0ull;           break;
        case Tyflt64:   return ~0ull;           break;

        /* complex types */
        case Typtr:     return 1;       break;
        case Tyarray:   return 1;       break;
        case Tytuple:   return 1;       break;
        case Tystruct:  return 1;
        case Tyunion:   return t->nmemb;        break;
        case Tyslice:   return ~0ULL;   break;

        case Tyvar: case Typaram: case Tyunres: case Tyname:
        case Tybad: case Tyvalist: case Tygeneric: case Ntypes:
        case Tyfunc: case Tycode:
            die("Invalid constructor type %s in match", tystr(t));
            break;
    }
    return 0;
}
Example #13
0
static Ucon *finducon(Node *n)
{
    size_t i;
    Type *t;
    Ucon *uc;

    t = tybase(n->expr.type);
    if (exprop(n) != Oucon)
        return NULL;
    for (i = 0; i  < t->nmemb; i++) {
        uc = t->udecls[i];
        if (!strcmp(namestr(uc->name), namestr(n->expr.args[0])))
            return uc;
    }
    die("No ucon?!?");
    return NULL;
}
Example #14
0
File: match.c Project: 8l/myrddin
static Dtree *addunion(Dtree *t, Node *pat, Node *val, Node ***cap, size_t *ncap)
{
    Node *elt, *tag, *id;
    int32_t t1, t2;
    Dtree *sub;
    Ucon *uc;
    size_t i;

    if (t->any)
        return t->any;
    uc = finducon(tybase(exprtype(pat)), pat->expr.args[0]);
    t2 = uc->id;
    /* if we have the value already... */
    sub = NULL;
    for (i = 0; i < t->nval; i++) {
        tag = t->val[i]->expr.args[0];
        t1 = tag->lit.intval;
        if (t1 == t2) {
            if (pat->expr.nargs > 1) {
                elt = uvalue(val, exprtype(pat->expr.args[1])); 
                return addpat(t->sub[i], pat->expr.args[1], elt, cap, ncap);
            } else {
                return t->sub[i];
            }
        }
    }

    /* otherwise create a new match */
    sub = mkdtree();
    sub->patexpr = pat;
    tag = mkexpr(pat->loc, Outag, val, NULL);
    tag->expr.type = mktype(pat->loc, Tyint32);

    id = mkintlit(pat->loc, uc->id);
    id->expr.type = mktype(pat->loc, Tyint32);

    lappend(&t->val, &t->nval, id);
    lappend(&t->sub, &t->nsub, sub);
    lappend(&t->load, &t->nload, tag);
    if (pat->expr.nargs == 2) {
        elt = uvalue(val, exprtype(pat->expr.args[1])); 
        sub = addpat(sub, pat->expr.args[1], elt, cap, ncap);
    }
    return sub;
}
Example #15
0
static Node *membaddr(Simp *s, Node *n)
{
    Node *t, *u, *r;
    Node **args;
    Type *ty;

    args = n->expr.args;
    ty = tybase(exprtype(args[0]));
    if (ty->type == Typtr) {
        t = lval(s, args[0]);
    } else {
        t = addr(s, lval(s, args[0]), exprtype(n));
    }
    u = disp(n->line, offset(args[0], args[1]));
    r = add(t, u);
    r->expr.type = mktyptr(n->line, n->expr.type);
    return r;
}
Example #16
0
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;
}
Example #17
0
int stacktype(Type *t)
{
    /* the types are arranged in types.def such that this is true */
    t = tybase(t);
    return t->type >= Tyslice;
}
Example #18
0
int floattype(Type *t)
{
    t = tybase(t);
    return t->type == Tyfloat32 || t->type == Tyfloat64;
}
Example #19
0
static void umatch(Simp *s, Node *pat, Node *val, Type *t, Node *iftrue, Node *iffalse)
{
    Node *v, *x, *y;
    Node *deeper, *next;
    Node **patarg;
    Ucon *uc;
    size_t i;
    size_t off;

    assert(pat->type == Nexpr);
    t = tybase(t);
    if (exprop(pat) == Ovar && !decls[pat->expr.did]->decl.isconst) {
        v = assign(s, pat, val);
        append(s, v);
        jmp(s, iftrue);
        return;
    }
    switch (t->type) {
        /* Never supported */
        case Tyvoid: case Tybad: case Tyvalist: case Tyvar:
        case Typaram: case Tyunres: case Tyname: case Ntypes:
        /* Should never show up */
        case Tyslice:
            die("Unsupported type for compare");
            break;
        case Tybool: case Tychar: case Tybyte:
        case Tyint8: case Tyint16: case Tyint32: case Tyint:
        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint:
        case Tyint64: case Tyuint64: case Tylong:  case Tyulong:
        case Tyfloat32: case Tyfloat64:
        case Typtr: case Tyfunc:
            v = mkexpr(pat->line, Oeq, pat, val, NULL);
            v->expr.type = mktype(pat->line, Tybool);
            cjmp(s, v, iftrue, iffalse);
            break;
        /* We got lucky. The structure of tuple, array, and struct literals
         * is the same, so long as we don't inspect the type, so we can
         * share the code*/
        case Tystruct: case Tytuple: case Tyarray: 
            patarg = pat->expr.args;
            off = 0;
            for (i = 0; i < pat->expr.nargs; i++) {
                off = tyalign(off, size(patarg[i]));
                next = genlbl();
                v = load(addk(addr(s, val, exprtype(patarg[i])), off));
                umatch(s, patarg[i], v, exprtype(patarg[i]), next, iffalse);
                append(s, next);
                off += size(patarg[i]);
            }
            jmp(s, iftrue);
            break;
        case Tyunion:
            uc = finducon(pat);
            if (!uc)
                uc = finducon(val);

            deeper = genlbl();

            x = uconid(s, pat);
            y = uconid(s, val);
            v = mkexpr(pat->line, Oeq, x, y, NULL);
            v->expr.type = tyintptr;
            cjmp(s, v, deeper, iffalse);
            append(s, deeper);
            if (uc->etype) {
                pat = patval(s, pat, uc->etype);
                val = patval(s, val, uc->etype);
                umatch(s, pat, val, uc->etype, iftrue, iffalse);
            }
            break;
    }
}
Example #20
0
static Node *simpcast(Simp *s, Node *val, Type *to)
{
    Node *r;
    Type *t;

    r = NULL;
    /* do the type conversion */
    switch (tybase(to)->type) {
        case Tybool:
        case Tyint8: case Tyint16: case Tyint32: case Tyint64:
        case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
        case Tyint: case Tyuint: case Tylong: case Tyulong:
        case Tychar: case Tybyte:
        case Typtr:
            t = tybase(exprtype(val));
            switch (t->type) {
                /* ptr -> slice conversion is disallowed */
                case Tyslice:
                    if (t->type == Typtr)
                        fatal(val->line, "Bad cast from %s to %s",
                              tystr(exprtype(val)), tystr(to));
                    r = slicebase(s, val, NULL);
                    break;
                /* signed conversions */
                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
                case Tyint: case Tylong:
                    r = intconvert(s, val, to, 1);
                    break;
                /* unsigned conversions */
                case Tybool:
                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
                case Tyuint: case Tyulong: case Tychar: case Tybyte:
                case Typtr:
                    r = intconvert(s, val, to, 0);
                    break;
                case Tyfloat32: case Tyfloat64:
                    if (tybase(to)->type == Typtr)
                        fatal(val->line, "Bad cast from %s to %s",
                              tystr(exprtype(val)), tystr(to));
                    r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL);
                    r->expr.type = to;
                    break;
                default:
                    fatal(val->line, "Bad cast from %s to %s",
                          tystr(exprtype(val)), tystr(to));
            }
            break;
        case Tyfloat32: case Tyfloat64:
            t = tybase(exprtype(val));
            switch (t->type) {
                case Tyint8: case Tyint16: case Tyint32: case Tyint64:
                case Tyuint8: case Tyuint16: case Tyuint32: case Tyuint64:
                case Tyint: case Tyuint: case Tylong: case Tyulong:
                case Tychar: case Tybyte:
                    r = mkexpr(val->line, Oflt2int, rval(s, val, NULL), NULL);
                    r->expr.type = to;
                    break;
                default:
                    fatal(val->line, "Bad cast from %s to %s",
                          tystr(exprtype(val)), tystr(to));
                    break;
            }
            break;
        /* no other destination types are handled as things stand */
        default:
            fatal(val->line, "Bad cast from %s to %s",
                  tystr(exprtype(val)), tystr(to));
    }
    return r;
}
Example #21
0
File: fold.c Project: 8l/mc
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;
}