commit 1dcded18a01420a8f57227792522897bcf919a88 Author: Roberto E. Vargas Caballero <k...@shike2.com> AuthorDate: Mon Aug 17 20:31:53 2015 +0200 Commit: Roberto E. Vargas Caballero <k...@shike2.com> CommitDate: Mon Aug 17 20:31:53 2015 +0200
Fix switch emittion Switch was broken in different ways. Case and default statements were not composed of label part and statement part, but only of the label part. This was not important except in this case: switch (x) case 1: switch (x) case 1: return 0; The output format for switch is also modified. diff --git a/cc1/cc1.h b/cc1/cc1.h index ea8ad78..659fd7e 100644 --- a/cc1/cc1.h +++ b/cc1/cc1.h @@ -82,6 +82,9 @@ struct scase { struct caselist { short nr; Symbol *deflabel; + Symbol *ltable; + Symbol *lbreak; + Node *expr; struct scase *head; }; @@ -282,6 +285,7 @@ enum op { ORET, ODECL, OSWITCH, + OSWITCHT, OAND, OOR, OEQ, diff --git a/cc1/code.c b/cc1/code.c index ec27c71..58bcfe6 100644 --- a/cc1/code.c +++ b/cc1/code.c @@ -7,7 +7,7 @@ #include "../inc/cc.h" #include "cc1.h" -static void emitbin(unsigned, void *), +static void emitbin(unsigned, void *), emitswitcht(unsigned, void *), emitcast(unsigned, void *), emitswitch(unsigned, void *), emitsym(unsigned, void *), emitexp(unsigned, void *), @@ -55,7 +55,7 @@ char *optxt[] = { [OCOMMA] = ",", [OLABEL] = "L%d\n", [ODEFAULT] = "\tf\tL%d\n", - [OCASE] = "\tw\tL%d", + [OCASE] = "\tv\tL%d", [OJUMP] = "\tj\tL%d\n", [OBRANCH] = "\tj\tL%d", [OEFUN] = "}", @@ -121,6 +121,7 @@ void (*opcode[])(unsigned, void *) = { [ORET] = emitret, [ODECL] = emitdcl, [OSWITCH] = emitswitch, + [OSWITCHT] = emitswitcht, [OPAR] = emitbin, [OCALL] = emitbin }; @@ -368,7 +369,25 @@ emitswitch(unsigned op, void *arg) { Caselist *lcase = arg; - printf("\teI\t#%0x", lcase->nr); + printf("\ts\tL%u", lcase->ltable->id); + emitexp(OEXPR, lcase->expr); +} + +static void +emitswitcht(unsigned op, void *arg) +{ + Caselist *lcase = arg; + struct scase *p, *next; + + printf("\tt\t#%0x\n", lcase->nr); + for (p = lcase->head; p; p = next) { + emitsymid(OCASE, p->label); + emitexp(OEXPR, p->expr); + next = p->next; + free(p); + } + if (lcase->deflabel) + emitsymid(ODEFAULT, lcase->deflabel); } Node * diff --git a/cc1/stmt.c b/cc1/stmt.c index 294ab5d..c89a131 100644 --- a/cc1/stmt.c +++ b/cc1/stmt.c @@ -189,14 +189,13 @@ static void Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) { Caselist lcase = {.nr = 0, .head = NULL, .deflabel = NULL}; - struct scase *p, *next; Node *cond; - Symbol *lcond; - void free(void *ptr); expect(SWITCH); expect ('('); - cond = expr(); + cond = eval(expr()); + /* TODO: why can I not call directly to convert here? */ + switch (BTYPE(cond)) { case INT: case ENUM: @@ -207,22 +206,16 @@ Switch(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) } expect (')'); - lbreak = newsym(NS_LABEL); - lcond = newsym(NS_LABEL); - emit(OJUMP, lcond); - stmt(lbreak, lcont, &lcase); - emit(OLABEL, lcond); + lcase.expr = cond; + lcase.lbreak = newsym(NS_LABEL); + lcase.ltable = newsym(NS_LABEL); + emit(OSWITCH, &lcase); - emit(OEXPR, cond); - for (p = lcase.head; p; p = next) { - emit(OCASE, p->label); - emit(OEXPR, p->expr); - next = p->next; - free(p); - } - if (lcase.deflabel) - emit(ODEFAULT, lcase.deflabel); - emit(OLABEL, lbreak); + stmt(lbreak, lcont, &lcase); + emit(OJUMP, lcase.lbreak); + emit(OLABEL, lcase.ltable); + emit(OSWITCHT, &lcase); + emit(OLABEL, lcase.lbreak); } static void @@ -243,6 +236,7 @@ Case(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) emit(OLABEL, pcase->label = newsym(NS_LABEL)); lswitch->head = pcase; ++lswitch->nr; + stmt(lbreak, lcont, lswitch); } static void @@ -254,6 +248,8 @@ Default(Symbol *lbreak, Symbol *lcont, Caselist *lswitch) expect(':'); emit(OLABEL, ldefault); lswitch->deflabel = ldefault; + ++lswitch->nr; + stmt(lbreak, lcont, lswitch); } static void diff --git a/cc1/tests/test012.c b/cc1/tests/test012.c new file mode 100644 index 0000000..0457aa8 --- /dev/null +++ b/cc1/tests/test012.c @@ -0,0 +1,111 @@ +/* +name: TEST012 +description: Basic switch test +output: +F1 +G1 F1 main +{ +- +A2 I x + A2 #I0 :I + s L4 A2 +L5 + j L3 +L4 + t #1 + v L5 #I0 +L3 + s L7 A2 +L8 + s L10 A2 +L11 + j L12 +L13 + yI #I1 + j L9 +L10 + t #2 + v L11 #I0 + f L13 +L9 + j L6 +L7 + t #1 + v L8 #I0 +L6 + yI #I2 +L12 + s L15 A2 +L16 + yI #I3 + j L14 +L15 + t #1 + v L16 #I1 +L14 + s L18 A2 + A2 #I2 :I +L19 +L20 + yI #I4 + j L17 +L18 + t #1 + v L20 #I1 +L17 + s L22 A2 +L23 + yI A2 +L24 + yI #I1 +L25 + yI #I1 + j L21 +L22 + t #3 + v L24 #I1 + v L23 #I0 + f L25 +L21 +} +*/ + + + +int +main() +{ + int x; + + x = 0; + switch(x) + case 0: + ; + switch(x) + case 0: + switch(x) { + case 0: + goto next; + default: + return 1; + } + return 2; + next: + switch(x) + case 1: + return 3; + switch(x) { + x = 1 + 1; + foo: + case 1: + return 4; + } + switch(x) { + case 0: + return x; + case 1: + return 1; + default: + return 1; + } +}