shithub: scc

Download patch

ref: 1dcded18a01420a8f57227792522897bcf919a88
parent: 6c7885a58e1d1202fbad71e09d423f8d637e25f8
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Mon Aug 17 16:31:53 EDT 2015

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.

--- a/cc1/cc1.h
+++ b/cc1/cc1.h
@@ -82,6 +82,9 @@
 struct caselist {
 	short nr;
 	Symbol *deflabel;
+	Symbol *ltable;
+	Symbol *lbreak;
+	Node *expr;
 	struct scase *head;
 };
 
@@ -282,6 +285,7 @@
 	ORET,
 	ODECL,
 	OSWITCH,
+	OSWITCHT,
 	OAND,
 	OOR,
 	OEQ,
--- 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 @@
 	[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 @@
 	[ORET] = emitret,
 	[ODECL] = emitdcl,
 	[OSWITCH] = emitswitch,
+	[OSWITCHT] = emitswitcht,
 	[OPAR] = emitbin,
 	[OCALL] = emitbin
 };
@@ -368,7 +369,25 @@
 {
 	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 *
--- a/cc1/stmt.c
+++ b/cc1/stmt.c
@@ -189,14 +189,13 @@
 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 @@
 	}
 	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 @@
 	emit(OLABEL, pcase->label = newsym(NS_LABEL));
 	lswitch->head = pcase;
 	++lswitch->nr;
+	stmt(lbreak, lcont, lswitch);
 }
 
 static void
@@ -254,6 +248,8 @@
 	expect(':');
 	emit(OLABEL, ldefault);
 	lswitch->deflabel = ldefault;
+	++lswitch->nr;
+	stmt(lbreak, lcont, lswitch);
 }
 
 static void
--- /dev/null
+++ b/cc1/tests/test012.c
@@ -1,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;
+	}
+}