commit 1dcded18a01420a8f57227792522897bcf919a88
parent 6c7885a58e1d1202fbad71e09d423f8d637e25f8
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Mon, 17 Aug 2015 20:31:53 +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.
Diffstat:
4 files changed, 152 insertions(+), 22 deletions(-)
diff --git 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
@@ -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
@@ -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
@@ -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;
+ }
+}