changeset 292:6d4231b6f9fe

switch statement prepare
author kono
date Sat, 05 Jun 2004 00:08:09 +0900
parents 7b6df595b205
children 5bf2c3070d36
files Changes mc-code-ia32.c mc-code-mips.c mc-code-powerpc.c mc-codegen.c mc-codegen.h mc-parse.c mc.h
diffstat 8 files changed, 154 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/Changes	Fri Jun 04 03:32:19 2004 +0900
+++ b/Changes	Sat Jun 05 00:08:09 2004 +0900
@@ -4606,3 +4606,30 @@
 
 code_bool で !use の時に、null branchが残っちゃうけど...
 ま、仕方がないか。
+
+Fri Jun  4 12:57:28 JST 2004
+
+switch 文をやるんだけど、
+
+       main() {
+           int i=3,j=1,k=0;
+           switch(i)  
+               for(;j<10;j++) {
+                   case 3: k++; case 2: k++; case 1: k++; case 0: k++;
+               }
+           printf("%d\n",k);
+       }
+
+なんだけど、j<10 などを評価する前にjmpする必要があるので、最
+初のcase文にjumpしないといけないが、jump する必要があるかど
+うかは、switch の次の文を実際に評価してみないとわからない。
+
+なので、 checkret() で、その処理を行う方が良い。
+     if (first_case) {
+         jmp(first_case); first_case =0;
+     }
+かな。もし、これが行われるなら、飛び先はtable jump routine であるべき。
+
+switch をまとめるのはやったけど、現状のコードだとtable
+は、ほとんどでないね。2分木は出るけど。IDが連続するように
+工夫した方がいいのかな。
--- a/mc-code-ia32.c	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-code-ia32.c	Sat Jun 05 00:08:09 2004 +0900
@@ -464,10 +464,9 @@
 void 
 gexpr_init(void)
 {
-    while(reg_sp > 0) {
-	if (reg_stack[--reg_sp]>=0)
-	    free_register(reg_stack[reg_sp]);
-    }
+    if (reg_sp>0) error(-1);
+    if (freg_sp>0) error(-1);
+    reg_sp = 0;
     freg_sp = 0;
     text_mode();
     gexpr_code_init();
--- a/mc-code-mips.c	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-code-mips.c	Sat Jun 05 00:08:09 2004 +0900
@@ -948,12 +948,15 @@
 gexpr_init(void)
 {
     while(reg_sp > 0) {
+	error(-1);
 	free_register(reg_stack[--reg_sp]);
     }
     while(freg_sp > 0) {
+	error(-1);
 	free_register(freg_stack[--freg_sp]);
     }
     while(lreg_sp > 0) {
+	error(-1);
 	free_register(lreg_stack[--lreg_sp]);
     }
     use_int0();
--- a/mc-code-powerpc.c	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-code-powerpc.c	Sat Jun 05 00:08:09 2004 +0900
@@ -915,12 +915,15 @@
 gexpr_init(void)
 {
     while(reg_sp > 0) {
+	error(-1);
 	free_register(reg_stack[--reg_sp]);
     }
     while(freg_sp > 0) {
+	error(-1);
 	free_register(freg_stack[--freg_sp]);
     }
     while(lreg_sp > 0) {
+	error(-1);
 	free_register(lreg_stack[--lreg_sp]);
     }
     use_int0();
--- a/mc-codegen.c	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-codegen.c	Sat Jun 05 00:08:09 2004 +0900
@@ -474,7 +474,7 @@
 {
     int op = car(e1);
     if (chk) return;
-    gexpr_init();
+    // gexpr_init();
     if (dual_ops(op) && (car(caddr(e1))==CONST||(car(caddr(e1))==DCONST)))
 	b_expr(list3(rop_dual(op),caddr(e1),cadr(e1)),cond,l1,0);
     else
@@ -1770,4 +1770,26 @@
     return 0;
 }
 
+#if CASE_CODE
+
+void
+cascade_compare(int cslist,int cslabel,int dlabel)
+{
+    fwddef(cslabel);
+    for(;cslist; cslist=cadr(cslist)) {
+	cmpdimm(car(cslist),csvalue1,caddr(cslist),0);
+    }
+    if (dlabel) jmp(dlabel);
+}
+
+void
+switch_table(int cslist,int cslabel,int dlabel)
+{
+    cascade_compare(cslist,cslabel,dlabel);
+}
+
+#endif
+
+
+
 /* end */
--- a/mc-codegen.h	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-codegen.h	Sat Jun 05 00:08:09 2004 +0900
@@ -20,6 +20,9 @@
 extern int backdef(void);
 extern int free_register_count(int);
 extern int fwdlabel(void);
+#if CASE_CODE
+extern void switch_table(int cslist,int cslabel,int dlabel);
+#endif
 extern void b_expr(int e1, char cond, int l1,int err);
 extern void bexpr(int e1, char cond, int l1);
 extern void emit_init(void);
--- a/mc-parse.c	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc-parse.c	Sat Jun 05 00:08:09 2004 +0900
@@ -1382,6 +1382,7 @@
     }
     conv->localvar_end_();
     control=1;
+    cslabel = -1;
     if(!chk) code_enter1(args);
     emit_init_vars();
     while(sym!=RC) statement();
@@ -1498,6 +1499,7 @@
     /* local variable declaration */
     local_decl();
     control=1;
+    cslabel = -1;
     if(!chk) enter1();
     emit_init_vars();
     while(sym!=RC) statement();
@@ -1603,7 +1605,10 @@
 static void
 checkret(void)
 {
-    if (retpending) {
+    if (cslabel==0) {
+	if (!control) error(-1); // no excute code in switch
+	jmp(cslabel=fwdlabel());
+    } else if (retpending) {
 	ret();
 	control=0;
 	retpending=0;
@@ -1619,7 +1624,6 @@
 	conv->sm_();
 	getsym(0); return;
     }
-    checkret();
     switch(sym) {
     case IF:
 	doif();
@@ -1640,14 +1644,16 @@
 	docomp();
 	return;
     case BREAK:
+	checkret();
 	conv->break_();
-	jmp(blabel);
+	if (control) jmp(blabel);
 	getsym(0);
 	checksym(SM);
 	return;
     case CONTINUE:
+	checkret();
 	conv->continue_();
-	jmp(clabel);
+	if (control) jmp(clabel);
 	getsym(0);
 	checksym(SM);
 	return;
@@ -1670,6 +1676,7 @@
 	    dolabel();
 	    statement();
 	} else {
+	    checkret();
 	    slfree=lfree;
 	    gexpr(expr(0),0);
 	    lfree=slfree;
@@ -1687,6 +1694,7 @@
     checksym(LPAR);
     conv->if_();
     slfree=lfree;
+    checkret();
     bexpr(expr(0),0,l1=fwdlabel());
     lfree=slfree;
     conv->if_then_();
@@ -1715,6 +1723,8 @@
     sbreak=blabel;
     scontinue=clabel;
     blabel=fwdlabel();
+    control=1;
+    checkret();
     clabel=backdef();
     conv->while_();
     getsym(0);
@@ -1751,6 +1761,8 @@
     scontinue=clabel;
     blabel=fwdlabel();
     clabel=fwdlabel();
+    control=1;
+    checkret();
     l=backdef();
     conv->dowhile_();
     getsym(0);
@@ -1784,6 +1796,7 @@
     checksym(LPAR);
     slfree=lfree;
     if(sym!=SM) {
+	checkret();
 	gexpr(expr(0),0);
 	checksym(SM);
 	conv->for1_();
@@ -1792,6 +1805,8 @@
 	getsym(0);
     }
     lfree=slfree;
+    control=1;
+    checkret();
     l=backdef();
     if(sym!=SM) {
 	bexpr(expr(0),0,blabel);
@@ -1827,10 +1842,23 @@
 }
 
 static void
+docomp(void)
+{
+    conv->lc_();
+    local_decl();
+    emit_init_vars();
+    while(sym!=RC) statement(); 
+    conv->rc_();
+    getsym(0);
+}
+
+static void
 doswitch(void)
 {
-    int sbreak,scase,sdefault,slfree,svalue;
-
+    int sbreak,scase,sdefault,slfree,svalue,slist;
+
+    checkret();
+    slist = cslist;
     sbreak=blabel;      /* save parents break label */
     blabel=fwdlabel();
     sdefault=dlabel;    /* save parents default label */
@@ -1847,37 +1875,66 @@
     checksym(RPAR);
     conv->switch_body_();
     cslabel = control = 0;
-    /* should be case statement but... */
+    /* should be case statement but...  for example,
+	main() {
+	    int i=3,j=1,k=0;
+	    switch(i)  {
+		for(;j<10;j++) {
+		    case 3: k++; case 2: k++; case 1: k++; case 0: k++;
+		}
+	    }
+	    printf("%d\n",k);
+	}
+       In this case, we have to jump into the first case label.
+       Can be done in checkret();
+    */
     statement();
     conv->switch_end_();
     checkret();
+#if CASE_CODE
+    if (control) jmp(blabel);
+    switch_table(cslist,cslabel,dlabel);
+#else
     if(dlabel) def_label(cslabel,dlabel);
     else fwddef(cslabel);
+#endif
     csvalue1=svalue;
     cslabel=scase;
     dlabel=sdefault;
     fwddef(blabel);
     blabel=sbreak;
-}
-
-static void
-docomp(void)
-{
-    conv->lc_();
-    local_decl();
-    emit_init_vars();
-    while(sym!=RC) { statement(); checkret();}
-    conv->rc_();
-    getsym(0);
+    cslist = slist;
 }
 
 static void
 docase(void)
 {
+#if CASE_CODE
+    int l;
+    l = fwdlabel();
+    while(sym==CASE) {
+	conv->case_begin_(0,0);
+	getsym(0);
+	cslist=list3(cexpr(expr(1)),cslist,l);
+	conv->case_(0,0);
+	checksym(COLON);
+    }
+    if (retpending) { ret(); retpending=0; }
+    if (!cslabel) {
+	if (!control) {
+	    // immiediate after switch(i) (ususal case)
+	    cmpdimm(car(cslist),csvalue1,cslabel=fwdlabel(),1);
+	    cslist = cadr(cslist);
+	} else error(-1);  // checkret() sequence inconsistent
+    }
+    fwddef(l);
+    control=1;
+#else
     int c,l,slfree;
-
+    l = 0;
+    if (retpending) ret();
+    slfree=lfree;
     c=0;
-    slfree=lfree;
     while(sym==CASE) {
 	conv->case_begin_(c,0);
 	getsym(0);
@@ -1885,28 +1942,29 @@
 	conv->case_(c,0);
 	checksym(COLON);
     }
-    l=fwdlabel();
     if (control) {
 	control=0;
-	jmp(l);
+	jmp(l=fwdlabel());
     }
     if (cslabel) fwddef(cslabel);
     while(cadr(c)) {
 	cmpdimm(car(c),csvalue1,l,0);
 	c=cadr(c);
     }
+    cmpdimm(car(c),csvalue1,cslabel=fwdlabel(),1);
+    if (l) fwddef(l);
     lfree=slfree;
-    cmpdimm(car(c),csvalue1,cslabel=fwdlabel(),1);
-    fwddef(l);
+#endif
 }
 
 static void
 dodefault(void)
 {
+    control=1;
+    checkret();
     getsym(0);
     checksym(COLON);
-    if (dlabel) error(STERR);
-    if (!cslabel) jmp(cslabel = fwdlabel());
+    if (dlabel) error(STERR);  // double default:
     dlabel = backdef();
     conv->case_(0,1);
 }
@@ -1916,7 +1974,9 @@
 {
     int slfree,e,e1;
 
+    if (!cslabel) jmp(cslabel = fwdlabel());
     if(getsym(0)==SM) {
+	// should check fnptr have no return value
 	conv->return_();
 	conv->return_end_();
 	getsym(0);
@@ -1966,6 +2026,7 @@
     NMTBL *nptr0;
     int t,e1,e2,env;
 
+    checkret();
     conv->goto_();
     getsym(0);
     e1 = expr(0);
@@ -2017,6 +2078,8 @@
 static void
 dolabel(void)
 {
+    control=1;
+    checkret();
     if(nptr->sc == FLABEL)
 	fwddef(nptr->dsp);
     else if(nptr->sc != EMPTY && nptr->sc != EXTRN1)
--- a/mc.h	Fri Jun 04 03:32:19 2004 +0900
+++ b/mc.h	Sat Jun 05 00:08:09 2004 +0900
@@ -12,6 +12,7 @@
 
 #define FLOAT_CODE 1
 #define LONGLONG_CODE 1
+#define CASE_CODE 1
 
 /* reserved word start */
 
@@ -411,7 +412,8 @@
 EXTERN int sym,ch,type,mode,stmode,gfree,lfree,mflag,lineno,glineno;
 EXTERN int labelno,gpc,disp,reg_var,debug;
 EXTERN int symval,args,init_vars,heap[HEAPSIZE];
-EXTERN int blabel,clabel,dlabel,cslabel,ilabel,control,ac,ac2,lsrc,chk,asmf;
+EXTERN int blabel,clabel,dlabel,cslist,cslabel,ilabel,control;
+EXTERN int ac,ac2,lsrc,chk,asmf;
 EXTERN int MAX_REGISTER_VAR;
 
 EXTERN unsigned hash;