diff options
author | Michael Forney <mforney@mforney.org> | 2021-03-28 15:48:08 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2021-03-31 02:55:26 -0700 |
commit | 207e3e4e683ed1c825db317fc07071e83d890932 (patch) | |
tree | 0e60481ac385b9278cb3c3084b23bcf3b65db8bd | |
parent | 4b74d8aa68fca6692782a47277e1dade5a2b039e (diff) |
qbe: Switch to fixed-size instruction struct
Move jump and phi instructions to struct block, and function arguments
to their own instruction.
This will facilitate allocating instructions as an array.
-rw-r--r-- | ops.h | 178 | ||||
-rw-r--r-- | qbe.c | 357 | ||||
-rw-r--r-- | test/float-to-uint64.qbe | 12 | ||||
-rw-r--r-- | test/uint64-to-float.qbe | 12 |
4 files changed, 302 insertions, 257 deletions
@@ -1,109 +1,101 @@ -/* jumps */ -OP(IJMP, 0, 1, "jmp") -OP(IJNZ, 0, 3, "jnz") -OP(IRET, 0, 1, "ret") - /* arithmetic and bits */ -OP(IADD, 1, 2, "add") -OP(ISUB, 1, 2, "sub") -OP(IDIV, 1, 2, "div") -OP(IMUL, 1, 2, "mul") -OP(IUDIV, 1, 2, "udiv") -OP(IREM, 1, 2, "rem") -OP(IUREM, 1, 2, "urem") -OP(IOR, 1, 2, "or") -OP(IXOR, 1, 2, "xor") -OP(IAND, 1, 2, "and") -OP(ISAR, 1, 2, "sar") -OP(ISHR, 1, 2, "shr") -OP(ISHL, 1, 2, "shl") +OP(IADD, "add") +OP(ISUB, "sub") +OP(IDIV, "div") +OP(IMUL, "mul") +OP(IUDIV, "udiv") +OP(IREM, "rem") +OP(IUREM, "urem") +OP(IOR, "or") +OP(IXOR, "xor") +OP(IAND, "and") +OP(ISAR, "sar") +OP(ISHR, "shr") +OP(ISHL, "shl") /* memory */ -OP(ISTORED, 0, 2, "stored") -OP(ISTORES, 0, 2, "stores") -OP(ISTOREL, 0, 2, "storel") -OP(ISTOREW, 0, 2, "storew") -OP(ISTOREH, 0, 2, "storeh") -OP(ISTOREB, 0, 2, "storeb") -OP(ILOADD, 1, 1, "loadd") -OP(ILOADS, 1, 1, "loads") -OP(ILOADL, 1, 1, "loadl") -OP(ILOADSW, 1, 1, "loadsw") -OP(ILOADUW, 1, 1, "loaduw") -OP(ILOADSH, 1, 1, "loadsh") -OP(ILOADUH, 1, 1, "loaduh") -OP(ILOADSB, 1, 1, "loadsb") -OP(ILOADUB, 1, 1, "loadub") -OP(IALLOC4, 1, 1, "alloc4") -OP(IALLOC8, 1, 1, "alloc8") -OP(IALLOC16, 1, 1, "alloc16") +OP(ISTORED, "stored") +OP(ISTORES, "stores") +OP(ISTOREL, "storel") +OP(ISTOREW, "storew") +OP(ISTOREH, "storeh") +OP(ISTOREB, "storeb") +OP(ILOADD, "loadd") +OP(ILOADS, "loads") +OP(ILOADL, "loadl") +OP(ILOADSW, "loadsw") +OP(ILOADUW, "loaduw") +OP(ILOADSH, "loadsh") +OP(ILOADUH, "loaduh") +OP(ILOADSB, "loadsb") +OP(ILOADUB, "loadub") +OP(IALLOC4, "alloc4") +OP(IALLOC8, "alloc8") +OP(IALLOC16, "alloc16") /* comparisons */ -OP(ICEQW, 1, 2, "ceqw") -OP(ICNEW, 1, 2, "cnew") -OP(ICSLEW, 1, 2, "cslew") -OP(ICSLTW, 1, 2, "csltw") -OP(ICSGEW, 1, 2, "csgew") -OP(ICSGTW, 1, 2, "csgtw") -OP(ICULEW, 1, 2, "culew") -OP(ICULTW, 1, 2, "cultw") -OP(ICUGEW, 1, 2, "cugew") -OP(ICUGTW, 1, 2, "cugtw") +OP(ICEQW, "ceqw") +OP(ICNEW, "cnew") +OP(ICSLEW, "cslew") +OP(ICSLTW, "csltw") +OP(ICSGEW, "csgew") +OP(ICSGTW, "csgtw") +OP(ICULEW, "culew") +OP(ICULTW, "cultw") +OP(ICUGEW, "cugew") +OP(ICUGTW, "cugtw") -OP(ICEQL, 1, 2, "ceql") -OP(ICNEL, 1, 2, "cnel") -OP(ICSLEL, 1, 2, "cslel") -OP(ICSLTL, 1, 2, "csltl") -OP(ICSGEL, 1, 2, "csgel") -OP(ICSGTL, 1, 2, "csgtl") -OP(ICULEL, 1, 2, "culel") -OP(ICULTL, 1, 2, "cultl") -OP(ICUGEL, 1, 2, "cugel") -OP(ICUGTL, 1, 2, "cugtl") +OP(ICEQL, "ceql") +OP(ICNEL, "cnel") +OP(ICSLEL, "cslel") +OP(ICSLTL, "csltl") +OP(ICSGEL, "csgel") +OP(ICSGTL, "csgtl") +OP(ICULEL, "culel") +OP(ICULTL, "cultl") +OP(ICUGEL, "cugel") +OP(ICUGTL, "cugtl") -OP(ICEQS, 1, 2, "ceqs") -OP(ICNES, 1, 2, "cnes") -OP(ICLES, 1, 2, "cles") -OP(ICLTS, 1, 2, "clts") -OP(ICGES, 1, 2, "cges") -OP(ICGTS, 1, 2, "cgts") -OP(ICOS, 1, 2, "cos") -OP(ICUOS, 1, 2, "cuos") +OP(ICEQS, "ceqs") +OP(ICNES, "cnes") +OP(ICLES, "cles") +OP(ICLTS, "clts") +OP(ICGES, "cges") +OP(ICGTS, "cgts") +OP(ICOS, "cos") +OP(ICUOS, "cuos") -OP(ICEQD, 1, 2, "ceqd") -OP(ICNED, 1, 2, "cned") -OP(ICLED, 1, 2, "cled") -OP(ICLTD, 1, 2, "cltd") -OP(ICGED, 1, 2, "cged") -OP(ICGTD, 1, 2, "cgtd") -OP(ICOD, 1, 2, "cod") -OP(ICUOD, 1, 2, "cuod") +OP(ICEQD, "ceqd") +OP(ICNED, "cned") +OP(ICLED, "cled") +OP(ICLTD, "cltd") +OP(ICGED, "cged") +OP(ICGTD, "cgtd") +OP(ICOD, "cod") +OP(ICUOD, "cuod") /* conversions */ -OP(IEXTSW, 1, 1, "extsw") -OP(IEXTUW, 1, 1, "extuw") -OP(IEXTSH, 1, 1, "extsh") -OP(IEXTUH, 1, 1, "extuh") -OP(IEXTSB, 1, 1, "extsb") -OP(IEXTUB, 1, 1, "extub") -OP(IEXTS, 1, 1, "exts") -OP(ITRUNCD, 1, 1, "truncd") -OP(ISTOSI, 1, 1, "stosi") -OP(IDTOSI, 1, 1, "dtosi") -OP(ISWTOF, 1, 1, "swtof") -OP(ISLTOF, 1, 1, "sltof") +OP(IEXTSW, "extsw") +OP(IEXTUW, "extuw") +OP(IEXTSH, "extsh") +OP(IEXTUH, "extuh") +OP(IEXTSB, "extsb") +OP(IEXTUB, "extub") +OP(IEXTS, "exts") +OP(ITRUNCD, "truncd") +OP(ISTOSI, "stosi") +OP(IDTOSI, "dtosi") +OP(ISWTOF, "swtof") +OP(ISLTOF, "sltof") /* cast and copy */ -OP(ICAST, 1, 1, "cast") -OP(ICOPY, 1, 1, "copy") +OP(ICAST, "cast") +OP(ICOPY, "copy") /* call */ -OP(ICALL, 1, -1, "call") -OP(IVACALL, 1, -1, "call") +OP(ICALL, "call") +OP(IVACALL, "call") /* variadic */ -OP(IVASTART, 0, 1, "vastart") -OP(IVAARG, 1, 1, "vaarg") - -/* phi */ -OP(IPHI, 1, -1, "phi") +OP(IVASTART, "vastart") +OP(IVAARG, "vaarg") @@ -45,20 +45,38 @@ struct lvalue { enum instkind { INONE, -#define OP(op, ret, arg, name) op, +#define OP(op, name) op, #include "ops.h" #undef OP + + IARG, }; struct inst { enum instkind kind; - struct value res, *arg[]; + struct value res, *arg[2]; +}; + +struct jump { + enum { + JUMP_NONE, + JUMP_JMP, + JUMP_JNZ, + JUMP_RET, + } kind; + struct value *arg; + struct value *blk[2]; }; struct block { struct value label; - bool terminated; struct array insts; + struct { + struct value *blk[2]; + struct value *val[2]; + struct value res; + } phi; + struct jump jump; struct block *next; }; @@ -108,8 +126,9 @@ mkblock(char *name) b->label.kind = VALUE_LABEL; b->label.name.str = name; b->label.name.id = ++id; - b->terminated = false; b->insts = (struct array){0}; + b->jump.kind = JUMP_NONE; + b->phi.res.kind = VALUE_NONE; b->next = NULL; return &b->label; @@ -192,47 +211,32 @@ functemp(struct func *f, struct value *v, struct repr *repr) v->repr = repr; } -static struct { - int ret, arg; - char *str; -} instdesc[] = { -#define OP(op, ret, arg, name) [op] = {ret, arg, name}, +static const char *instname[] = { +#define OP(op, name) [op] = name, #include "ops.h" #undef OP }; static struct value * -funcinstn(struct func *f, int op, struct repr *repr, struct value *args[]) +funcinst(struct func *f, int op, struct repr *repr, struct value *arg0, struct value *arg1) { struct inst *inst; - size_t n; - if (f->end->terminated) + if (f->end->jump.kind) return NULL; - n = instdesc[op].arg; - if (n == -1) { - for (n = 0; args[n]; ++n) - ; - ++n; - } - if (n > (SIZE_MAX - sizeof(*inst)) / sizeof(args[0])) { - errno = ENOMEM; - fatal("malloc:"); - } - inst = xmalloc(sizeof(*inst) + n * sizeof(args[0])); + inst = xmalloc(sizeof(*inst)); inst->kind = op; + inst->arg[0] = arg0; + inst->arg[1] = arg1; if (repr) functemp(f, &inst->res, repr); else inst->res.kind = VALUE_NONE; - memcpy(inst->arg, args, n * sizeof(args[0])); arrayaddptr(&f->end->insts, inst); - return instdesc[op].ret ? &inst->res : NULL; + return &inst->res; } -#define funcinst(f, op, repr, ...) funcinstn(f, op, repr, (struct value *[]){__VA_ARGS__}) - static void funcalloc(struct func *f, struct decl *d) { @@ -254,10 +258,11 @@ funcalloc(struct func *f, struct decl *d) default: fatal("internal error: invalid alignment: %d\n", d->align); } - inst = xmalloc(sizeof(*inst) + sizeof(inst->arg[0])); + inst = xmalloc(sizeof(*inst)); inst->kind = op; functemp(f, &inst->res, &iptr); inst->arg[0] = mkintconst(&i64, d->type->size); + inst->arg[1] = NULL; d->value = &inst->res; arrayaddptr(&f->start->insts, inst); } @@ -306,7 +311,7 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, dst = lval.addr; align = mkintconst(&iptr, t->align); for (offset = 0; offset < t->size; offset += t->align) { - tmp = funcinst(f, loadop, &iptr, src); + tmp = funcinst(f, loadop, &iptr, src, NULL); funcinst(f, storeop, NULL, tmp, dst); src = funcinst(f, IADD, &iptr, src, align); dst = funcinst(f, IADD, &iptr, dst, align); @@ -333,9 +338,9 @@ funcstore(struct func *f, struct type *t, enum typequal tq, struct lvalue lval, v = funcinst(f, IAND, t->repr, v, mkintconst(t->repr, mask)); v = funcinst(f, IOR, t->repr, v, funcinst(f, IAND, t->repr, - funcinst(f, loadop, t->repr, lval.addr), - mkintconst(t->repr, ~mask), - ), + funcinst(f, loadop, t->repr, lval.addr, NULL), + mkintconst(t->repr, ~mask) + ) ); } funcinst(f, storeop, NULL, v, lval.addr); @@ -372,7 +377,7 @@ funcload(struct func *f, struct type *t, struct lvalue lval) fatal("internal error; unimplemented load"); } } - v = funcinst(f, op, t->repr, lval.addr); + v = funcinst(f, op, t->repr, lval.addr, NULL); return funcbits(f, t, v, lval.bits); } @@ -380,67 +385,71 @@ funcload(struct func *f, struct type *t, struct lvalue lval) static struct value * utof(struct func *f, struct repr *r, struct value *v) { - struct value *odd, *big, *phi[5] = {0}, *join; + struct value *odd, *big; + struct block *join; if (v->repr->base == 'w') { - v = funcinst(f, IEXTUW, &i64, v); - return funcinst(f, ISLTOF, r, v); + v = funcinst(f, IEXTUW, &i64, v, NULL); + return funcinst(f, ISLTOF, r, v, NULL); } - phi[0] = mkblock("utof_small"); - phi[2] = mkblock("utof_big"); - join = mkblock("utof_join"); + join = (struct block *)mkblock("utof_join"); + join->phi.blk[0] = mkblock("utof_small"); + join->phi.blk[1] = mkblock("utof_big"); big = funcinst(f, ICSLTL, &i32, v, mkintconst(&i64, 0)); - funcjnz(f, big, phi[2], phi[0]); + funcjnz(f, big, join->phi.blk[1], join->phi.blk[0]); - funclabel(f, phi[0]); - phi[1] = funcinst(f, ISLTOF, r, v); - funcjmp(f, join); + funclabel(f, join->phi.blk[0]); + join->phi.val[0] = funcinst(f, ISLTOF, r, v, NULL); + funcjmp(f, &join->label); - funclabel(f, phi[2]); + funclabel(f, join->phi.blk[1]); odd = funcinst(f, IAND, &i64, v, mkintconst(&i64, 1)); v = funcinst(f, ISHR, &i64, v, mkintconst(&i64, 1)); v = funcinst(f, IOR, &i64, v, odd); /* round to odd */ - v = funcinst(f, ISLTOF, r, v); - phi[3] = funcinst(f, IADD, r, v, v); + v = funcinst(f, ISLTOF, r, v, NULL); + join->phi.val[1] = funcinst(f, IADD, r, v, v); - funclabel(f, join); - return funcinstn(f, IPHI, r, phi); + funclabel(f, &join->label); + functemp(f, &join->phi.res, r); + return &join->phi.res; } static struct value * ftou(struct func *f, struct repr *r, struct value *v) { - struct value *big, *phi[5] = {0}, *join, *maxflt, *maxint; + struct value *big, *maxflt, *maxint; + struct block *join; enum instkind op = v->repr->base == 's' ? ISTOSI : IDTOSI; if (r->base == 'w') { - v = funcinst(f, op, &i64, v); - return funcinst(f, ICOPY, r, v); + v = funcinst(f, op, &i64, v, NULL); + return funcinst(f, ICOPY, r, v, NULL); } - phi[0] = mkblock("ftou_small"); - phi[2] = mkblock("ftou_big"); - join = mkblock("ftou_join"); + join = (struct block *)mkblock("ftou_join"); + join->phi.blk[0] = mkblock("ftou_small"); + join->phi.blk[1] = mkblock("ftou_big"); maxflt = mkfltconst(v->repr, 0x1p63); maxint = mkintconst(&i64, 1ull<<63); big = funcinst(f, v->repr->base == 's' ? ICGES : ICGED, &i32, v, maxflt); - funcjnz(f, big, phi[2], phi[0]); + funcjnz(f, big, join->phi.blk[1], join->phi.blk[0]); - funclabel(f, phi[0]); - phi[1] = funcinst(f, op, r, v); - funcjmp(f, join); + funclabel(f, join->phi.blk[0]); + join->phi.val[0] = funcinst(f, op, r, v, NULL); + funcjmp(f, &join->label); - funclabel(f, phi[2]); + funclabel(f, join->phi.blk[1]); v = funcinst(f, ISUB, v->repr, v, maxflt); - v = funcinst(f, op, r, v); - phi[3] = funcinst(f, IXOR, r, v, maxint); + v = funcinst(f, op, r, v, NULL); + join->phi.val[1] = funcinst(f, IXOR, r, v, maxint); - funclabel(f, join); - return funcinstn(f, IPHI, r, phi); + funclabel(f, &join->label); + functemp(f, &join->phi.res, r); + return &join->phi.res; } static struct value * @@ -453,7 +462,7 @@ extend(struct func *f, struct type *t, struct value *v) case 2: op = t->basic.issigned ? IEXTSH : IEXTUH; break; default: return v; } - return funcinst(f, op, &i32, v); + return funcinst(f, op, &i32, v, NULL); } static struct value * @@ -599,24 +608,38 @@ funclabel(struct func *f, struct value *v) } void -funcjmp(struct func *f, struct value *v) +funcjmp(struct func *f, struct value *l) { - funcinst(f, IJMP, NULL, v); - f->end->terminated = true; + struct block *b = f->end; + + if (!b->jump.kind) { + b->jump.kind = JUMP_JMP; + b->jump.blk[0] = l; + } } void funcjnz(struct func *f, struct value *v, struct value *l1, struct value *l2) { - funcinst(f, IJNZ, NULL, v, l1, l2); - f->end->terminated = true; + struct block *b = f->end; + + if (!b->jump.kind) { + b->jump.kind = JUMP_JNZ; + b->jump.arg = v; + b->jump.blk[0] = l1; + b->jump.blk[1] = l2; + } } void funcret(struct func *f, struct value *v) { - funcinst(f, IRET, NULL, v); - f->end->terminated = true; + struct block *b = f->end; + + if (!b->jump.kind) { + b->jump.kind = JUMP_RET; + b->jump.arg = v; + } } struct gotolabel * @@ -678,7 +701,7 @@ funclval(struct func *f, struct expr *e) default: if (e->type->kind != TYPESTRUCT && e->type->kind != TYPEUNION) error(&tok.loc, "expression is not an object"); - lval.addr = funcinst(f, ICOPY, &iptr, funcexpr(f, e)); + lval.addr = funcinst(f, ICOPY, &iptr, funcexpr(f, e), NULL); } return lval; } @@ -688,11 +711,12 @@ funcexpr(struct func *f, struct expr *e) { enum instkind op = INONE; struct decl *d; - struct value *l, *r, *v, **argvals, **argval; + struct value *l, *r, *v, **argvals; struct lvalue lval; struct expr *arg; - struct value *label[5]; + struct block *join; struct type *t; + size_t i; switch (e->kind) { case EXPRIDENT: @@ -727,17 +751,16 @@ funcexpr(struct func *f, struct expr *e) v = funcstore(f, e->type, e->qual, lval, v); return e->incdec.post ? l : v; case EXPRCALL: - argvals = xreallocarray(NULL, e->call.nargs + 3, sizeof(argvals[0])); - argvals[0] = funcexpr(f, e->base); - emittype(e->type); - for (argval = &argvals[1], arg = e->call.args; arg; ++argval, arg = arg->next) { + op = e->base->type->base->func.isvararg ? IVACALL : ICALL; + argvals = xreallocarray(NULL, e->call.nargs, sizeof(argvals[0])); + for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) { emittype(arg->type); - *argval = funcexpr(f, arg); + argvals[i] = funcexpr(f, arg); } - *argval = NULL; - op = e->base->type->base->func.isvararg ? IVACALL : ICALL; - v = funcinstn(f, op, e->type == &typevoid ? NULL : e->type->repr, argvals); - free(argvals); + emittype(e->type); + v = funcinst(f, op, e->type->repr, funcexpr(f, e->base), NULL); + for (arg = e->call.args, i = 0; arg; arg = arg->next, ++i) + funcinst(f, IARG, NULL, argvals[i], NULL); //if (e->base->type->base->func.isnoreturn) // funcret(f, NULL); return v; @@ -757,20 +780,20 @@ funcexpr(struct func *f, struct expr *e) return convert(f, e->type, e->base->type, l); case EXPRBINARY: if (e->op == TLOR || e->op == TLAND) { - label[0] = mkblock("logic_right"); - label[1] = mkblock("logic_join"); - - l = funcexpr(f, e->binary.l); - label[2] = (struct value *)f->end; + r = mkblock("logic_right"); + join = (struct block *)mkblock("logic_join"); + join->phi.val[0] = funcexpr(f, e->binary.l); + join->phi.blk[0] = &f->end->label; if (e->op == TLOR) - funcjnz(f, l, label[1], label[0]); + funcjnz(f, join->phi.val[0], &join->label, r); else - funcjnz(f, l, label[0], label[1]); - funclabel(f, label[0]); - r = funcexpr(f, e->binary.r); - label[3] = (struct value *)f->end; - funclabel(f, label[1]); - return funcinst(f, IPHI, e->type->repr, label[2], l, label[3], r, NULL); + funcjnz(f, join->phi.val[0], r, &join->label); + funclabel(f, r); + join->phi.val[1] = funcexpr(f, e->binary.r); + join->phi.blk[1] = &f->end->label; + funclabel(f, &join->label); + functemp(f, &join->phi.res, e->type->repr); + return &join->phi.res; } l = funcexpr(f, e->binary.l); r = funcexpr(f, e->binary.r); @@ -861,26 +884,27 @@ funcexpr(struct func *f, struct expr *e) fatal("internal error; unimplemented binary expression"); return funcinst(f, op, e->type->repr, l, r); case EXPRCOND: - label[0] = mkblock("cond_true"); - label[1] = mkblock("cond_false"); - label[2] = mkblock("cond_join"); + l = mkblock("cond_true"); + r = mkblock("cond_false"); + join = (struct block *)mkblock("cond_join"); v = funcexpr(f, e->base); - funcjnz(f, v, label[0], label[1]); + funcjnz(f, v, l, r); - funclabel(f, label[0]); - l = funcexpr(f, e->cond.t); - label[3] = (struct value *)f->end; - funcjmp(f, label[2]); + funclabel(f, l); + join->phi.val[0] = funcexpr(f, e->cond.t); + join->phi.blk[0] = &f->end->label; + funcjmp(f, &join->label); - funclabel(f, label[1]); - r = funcexpr(f, e->cond.f); - label[4] = (struct value *)f->end; + funclabel(f, r); + join->phi.val[1] = funcexpr(f, e->cond.f); + join->phi.blk[1] = &f->end->label; - funclabel(f, label[2]); + funclabel(f, &join->label); if (e->type == &typevoid) return NULL; - return funcinst(f, IPHI, e->type->repr, label[3], l, label[4], r, NULL); + functemp(f, &join->phi.res, e->type->repr); + return &join->phi.res; case EXPRASSIGN: r = funcexpr(f, e->assign.r); if (e->assign.l->kind == EXPRTEMP) { @@ -898,20 +922,20 @@ funcexpr(struct func *f, struct expr *e) switch (e->builtin.kind) { case BUILTINVASTART: l = funcexpr(f, e->base); - funcinst(f, IVASTART, NULL, l); + funcinst(f, IVASTART, NULL, l, NULL); break; case BUILTINVAARG: /* https://todo.sr.ht/~mcf/cproc/52 */ if (!(e->type->prop & PROPSCALAR)) error(&tok.loc, "va_arg with non-scalar type is not yet supported"); l = funcexpr(f, e->base); - return funcinst(f, IVAARG, e->type->repr, l); + return funcinst(f, IVAARG, e->type->repr, l, NULL); case BUILTINVAEND: /* no-op */ break; case BUILTINALLOCA: l = funcexpr(f, e->base); - return funcinst(f, IALLOC16, &iptr, l); + return funcinst(f, IALLOC16, &iptr, l, NULL); default: fatal("internal error: unimplemented builtin"); } @@ -1124,75 +1148,90 @@ emittype(struct type *t) puts("}"); } -static void -emitinst(struct inst *inst) +static struct inst ** +emitinst(struct inst **instp, struct inst **instend) { - struct value **arg; + int op, first; + struct inst *inst = *instp; putchar('\t'); - assert(inst->kind < LEN(instdesc)); - if (instdesc[inst->kind].ret && inst->res.kind) { + assert(inst->kind < LEN(instname)); + if (inst->res.kind) { emitvalue(&inst->res); fputs(" =", stdout); emitrepr(inst->res.repr, inst->kind == ICALL || inst->kind == IVACALL, false); putchar(' '); } - fputs(instdesc[inst->kind].str, stdout); - switch (inst->kind) { + fputs(instname[inst->kind], stdout); + putchar(' '); + emitvalue(inst->arg[0]); + ++instp; + op = inst->kind; + switch (op) { case ICALL: case IVACALL: - putchar(' '); - emitvalue(inst->arg[0]); putchar('('); - for (arg = &inst->arg[1]; *arg; ++arg) { - if (arg != &inst->arg[1]) + for (first = 1; instp != instend && (*instp)->kind == IARG; ++instp) { + if (first) + first = 0; + else fputs(", ", stdout); - emitrepr((*arg)->repr, true, false); + inst = *instp; + emitrepr(inst->arg[0]->repr, true, false); putchar(' '); - emitvalue(*arg); + emitvalue(inst->arg[0]); } - if (inst->kind == IVACALL) + if (op == IVACALL) fputs(", ...", stdout); putchar(')'); break; - case IPHI: - putchar(' '); - for (arg = inst->arg; *arg; ++arg) { - if (arg != inst->arg) - fputs(", ", stdout); - emitvalue(*arg); - putchar(' '); - emitvalue(*++arg); - } - break; - case IRET: - if (!inst->arg[0]) - break; - /* fallthrough */ default: - putchar(' '); - emitvalue(inst->arg[0]); - if (instdesc[inst->kind].arg > 1) { + if (inst->arg[1]) { fputs(", ", stdout); emitvalue(inst->arg[1]); } - if (instdesc[inst->kind].arg > 2) { - fputs(", ", stdout); - emitvalue(inst->arg[2]); - } } putchar('\n'); + return instp; +} + +static void +emitjump(struct jump *j) +{ + switch (j->kind) { + case JUMP_RET: + fputs("\tret", stdout); + if (j->arg) { + fputc(' ', stdout); + emitvalue(j->arg); + } + putchar('\n'); + break; + case JUMP_JMP: + fputs("\tjmp ", stdout); + emitvalue(j->blk[0]); + putchar('\n'); + break; + case JUMP_JNZ: + fputs("\tjnz ", stdout); + emitvalue(j->arg); + fputs(", ", stdout); + emitvalue(j->blk[0]); + fputs(", ", stdout); + emitvalue(j->blk[1]); + putchar('\n'); + break; + } } void emitfunc(struct func *f, bool global) { struct block *b; - struct inst **inst; + struct inst **inst, **instend; struct param *p; - size_t n; - if (!f->end->terminated) + if (f->end->jump.kind == JUMP_NONE) funcret(f, strcmp(f->name, "main") == 0 ? mkintconst(&i32, 0) : NULL); if (global) puts("export"); @@ -1216,9 +1255,23 @@ emitfunc(struct func *f, bool global) for (b = f->start; b; b = b->next) { emitvalue(&b->label); putchar('\n'); - n = b->insts.len / sizeof(*inst); - for (inst = b->insts.val; n; --n, ++inst) - emitinst(*inst); + if (b->phi.res.kind) { + putchar('\t'); + emitvalue(&b->phi.res); + printf(" =%c phi ", b->phi.res.repr->base); + emitvalue(b->phi.blk[0]); + putchar(' '); + emitvalue(b->phi.val[0]); + fputs(", ", stdout); + emitvalue(b->phi.blk[1]); + putchar(' '); + emitvalue(b->phi.val[1]); + putchar('\n'); + } + instend = (struct inst **)((char *)b->insts.val + b->insts.len); + for (inst = b->insts.val; inst != instend;) + inst = emitinst(inst, instend); + emitjump(&b->jump); } puts("}"); } diff --git a/test/float-to-uint64.qbe b/test/float-to-uint64.qbe index b19ff32..dbe746e 100644 --- a/test/float-to-uint64.qbe +++ b/test/float-to-uint64.qbe @@ -4,15 +4,15 @@ function l $f() { @body.2 %.1 =s call $g() %.2 =w cges %.1, s_9223372036854775808 - jnz %.2, @ftou_big.4, @ftou_small.3 -@ftou_small.3 + jnz %.2, @ftou_big.5, @ftou_small.4 +@ftou_small.4 %.3 =l stosi %.1 - jmp @ftou_join.5 -@ftou_big.4 + jmp @ftou_join.3 +@ftou_big.5 %.4 =s sub %.1, s_9223372036854775808 %.5 =l stosi %.4 %.6 =l xor %.5, 9223372036854775808 -@ftou_join.5 - %.7 =l phi @ftou_small.3 %.3, @ftou_big.4 %.6 +@ftou_join.3 + %.7 =l phi @ftou_small.4 %.3, @ftou_big.5 %.6 ret %.7 } diff --git a/test/uint64-to-float.qbe b/test/uint64-to-float.qbe index 6542c29..4c3cf92 100644 --- a/test/uint64-to-float.qbe +++ b/test/uint64-to-float.qbe @@ -4,17 +4,17 @@ function s $f() { @body.2 %.1 =l call $g() %.2 =w csltl %.1, 0 - jnz %.2, @utof_big.4, @utof_small.3 -@utof_small.3 + jnz %.2, @utof_big.5, @utof_small.4 +@utof_small.4 %.3 =s sltof %.1 - jmp @utof_join.5 -@utof_big.4 + jmp @utof_join.3 +@utof_big.5 %.4 =l and %.1, 1 %.5 =l shr %.1, 1 %.6 =l or %.5, %.4 %.7 =s sltof %.6 %.8 =s add %.7, %.7 -@utof_join.5 - %.9 =s phi @utof_small.3 %.3, @utof_big.4 %.8 +@utof_join.3 + %.9 =s phi @utof_small.4 %.3, @utof_big.5 %.8 ret %.9 } |