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;
+       }
+}

Reply via email to