diff options
Diffstat (limited to 'qbe.c')
-rw-r--r-- | qbe.c | 57 |
1 files changed, 50 insertions, 7 deletions
@@ -95,6 +95,10 @@ struct func { struct block *start, *end; struct map gotos; unsigned lastid; + bool deferring; + struct { + struct block *start, *end, *deferred; + } defer; }; static const int ptrclass = 'l'; @@ -244,14 +248,14 @@ static struct value * funcinst(struct func *f, int op, int class, struct value *arg0, struct value *arg1) { struct inst *inst; - struct block *b; + struct block *b, *end = f->deferring ? f->defer.end : f->end; - if (f->end->jump.kind) { + if (end->jump.kind) { b = mkblock("dead"); funclabel(f, b); } inst = mkinst(f, op, class, arg0, arg1); - arrayaddptr(&f->end->insts, inst); + arrayaddptr(&end->insts, inst); return &inst->res; } @@ -512,6 +516,9 @@ mkfunc(struct decl *decl, char *name, struct type *t, struct scope *s) f->type = t; f->start = f->end = mkblock("start"); f->lastid = 0; + f->defer.start = f->defer.end = mkblock("defer"); + f->defer.deferred = NULL; + f->deferring = false; mapinit(&f->gotos, 8); emittype(t->base); @@ -566,16 +573,48 @@ functype(struct func *f) } void +funcstartdefer(struct func *f) +{ + f->deferring = true; +} + +void +funcenddefer(struct func *f) +{ + f->deferring = false; + f->defer.end->next = f->defer.deferred; + f->defer.deferred = f->defer.start; + f->defer.start = f->defer.end = mkblock("defer"); +} + +void +funcdefer(struct func *f) +{ + if (!f->defer.deferred || f->deferring) + return; + f->end->next = f->defer.deferred; + while (f->defer.deferred->next) + f->defer.deferred = f->defer.deferred->next; + f->end = f->defer.deferred; + f->defer.deferred = NULL; +} + +void funclabel(struct func *f, struct block *b) { - f->end->next = b; - f->end = b; + if (f->deferring) { + f->defer.end->next = b; + f->defer.end = b; + } else { + f->end->next = b; + f->end = b; + } } void funcjmp(struct func *f, struct block *l) { - struct block *b = f->end; + struct block *b = f->deferring ? f->defer.end : f->end; if (!b->jump.kind) { b->jump.kind = JUMP_JMP; @@ -586,7 +625,7 @@ funcjmp(struct func *f, struct block *l) void funcjnz(struct func *f, struct value *v, struct type *t, struct block *l1, struct block *l2) { - struct block *b = f->end; + struct block *b = f->deferring ? f->defer.end : f->end; if (b->jump.kind) return; @@ -613,6 +652,10 @@ funcret(struct func *f, struct value *v) { struct block *b = f->end; + if (f->deferring) { + error(&tok.loc, "cannot return from defer block."); + } + if (!b->jump.kind) { b->jump.kind = JUMP_RET; b->jump.arg = v; |