From 186b7095eeb84bec527d6d7ac9320776a8b78734 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Fri, 26 Apr 2024 18:31:18 -0700 Subject: Use hlt to implement noreturn --- cc.h | 1 + decl.c | 2 ++ qbe.c | 29 ++++++++++++++++++++++++----- test/func-noreturn.c | 13 +++++++++++++ test/func-noreturn.qbe | 28 ++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 test/func-noreturn.c create mode 100644 test/func-noreturn.qbe diff --git a/cc.h b/cc.h index 1cd1b32..ea237c5 100644 --- a/cc.h +++ b/cc.h @@ -556,6 +556,7 @@ struct value *funcexpr(struct func *, struct expr *); void funcjmp(struct func *, struct block *); void funcjnz(struct func *, struct value *, struct type *, struct block *, struct block *); void funcret(struct func *, struct value *); +void funchlt(struct func *); struct gotolabel *funcgoto(struct func *, char *); void funcswitch(struct func *, struct value *, struct switchcases *, struct block *); void funcinit(struct func *, struct decl *, struct init *, bool); diff --git a/decl.c b/decl.c index 0749017..39c272d 100644 --- a/decl.c +++ b/decl.c @@ -1066,6 +1066,8 @@ decl(struct scope *s, struct func *f) s = funcscope; f = mkfunc(d, name, t, s); stmt(f, s); + if (d->u.func.isnoreturn) + funchlt(f); /* XXX: need to keep track of function in case a later declaration specifies extern */ if (!d->u.func.inlinedefn) emitfunc(f, d->linkage == LINKEXTERN); diff --git a/qbe.c b/qbe.c index a6781dd..5c76bb2 100644 --- a/qbe.c +++ b/qbe.c @@ -62,6 +62,7 @@ struct jump { JUMP_JMP, JUMP_JNZ, JUMP_RET, + JUMP_HLT, } kind; struct value *arg; struct block *blk[2]; @@ -598,6 +599,15 @@ funcret(struct func *f, struct value *v) } } +void +funchlt(struct func *f) +{ + struct block *b = f->end; + + if (!b->jump.kind) + b->jump.kind = JUMP_HLT; +} + struct gotolabel * funcgoto(struct func *f, char *name) { @@ -631,7 +641,7 @@ funclval(struct func *f, struct expr *e) case EXPRIDENT: d = e->u.ident.decl; if (d->kind != DECLOBJECT && d->kind != DECLFUNC) - error(&tok.loc, "identifier is not an object or function"); /* XXX: fix location, var name */ + error(&tok.loc, "identifier '%s' is not an object or function", d->name); if (d == f->namedecl) { fputs("data ", stdout); emitname(d->value); @@ -727,10 +737,12 @@ funcexpr(struct func *f, struct expr *e) t = arg->type; funcinst(f, IARG, qbetype(t).base, argvals[i], t->value); } - /* - if (functype->func.isnoreturn) - funcret(f, NULL); - */ + e = e->base; + if (e->kind == EXPRUNARY && e->op == TBAND) { + e = e->base; + if (e->kind == EXPRIDENT && e->u.ident.decl->u.func.isnoreturn) + funchlt(f); + } return v; case EXPRUNARY: switch (e->op) { @@ -1187,6 +1199,8 @@ static void emitjump(struct jump *j) { switch (j->kind) { + case JUMP_NONE: + break; case JUMP_RET: fputs("\tret", stdout); if (j->arg) { @@ -1209,6 +1223,11 @@ emitjump(struct jump *j) emitname(&j->blk[1]->label); putchar('\n'); break; + case JUMP_HLT: + fputs("\thlt\n", stdout); + break; + default: + assert(0); } } diff --git a/test/func-noreturn.c b/test/func-noreturn.c new file mode 100644 index 0000000..0cd7f7a --- /dev/null +++ b/test/func-noreturn.c @@ -0,0 +1,13 @@ +_Noreturn void exit(int); +int puts(const char *); +void _Noreturn f(void) { + static int c; + while (c) + puts("loop"); +} +int main(void) { + exit(0); + (*f)(); + (***f)(); + return 1; +} diff --git a/test/func-noreturn.qbe b/test/func-noreturn.qbe new file mode 100644 index 0000000..d1771dc --- /dev/null +++ b/test/func-noreturn.qbe @@ -0,0 +1,28 @@ +data $.Lc.2 = align 4 { z 4 } +data $.Lstring.3 = align 1 { b "loop\000", } +export +function $f() { +@start.1 +@body.2 +@while_cond.3 + %.1 =w loadw $.Lc.2 + jnz %.1, @while_body.4, @while_join.5 +@while_body.4 + %.2 =w call $puts(l $.Lstring.3) + jmp @while_cond.3 +@while_join.5 + hlt +} +export +function w $main() { +@start.6 +@body.7 + call $exit(w 0) + hlt +@dead.8 + call $f() + hlt +@dead.9 + call $f() + hlt +} -- cgit v1.2.3