148116Sbostic /*-
2*62213Sbostic * Copyright (c) 1980, 1993
3*62213Sbostic * The Regents of the University of California. All rights reserved.
448116Sbostic *
548116Sbostic * %sccs.include.redist.c%
622182Sdist */
7763Speter
815936Smckusick #ifndef lint
9*62213Sbostic static char sccsid[] = "@(#)pccaseop.c 8.1 (Berkeley) 06/06/93";
1048116Sbostic #endif /* not lint */
11763Speter
12763Speter #include "whoami.h"
13763Speter #ifdef PC
14763Speter /*
15763Speter * and the rest of the file
16763Speter */
17763Speter #include "0.h"
18763Speter #include "tree.h"
19763Speter #include "objfmt.h"
2018463Sralph #include <pcc.h>
21763Speter #include "pc.h"
2211329Speter #include "tmps.h"
2315936Smckusick #include "tree_ty.h"
24926Speter
25763Speter /*
26926Speter * structure for a case:
27926Speter * its constant label, line number (for errors), and location label.
28926Speter */
29926Speter struct ct {
30926Speter long cconst;
31926Speter int cline;
32926Speter int clabel;
33926Speter };
34926Speter
35926Speter /*
3618463Sralph * the PCC_FORCE operator puts its operand into a register.
37926Speter * these to keep from thinking of it as r0 all over.
38926Speter */
3930032Smckusick #if defined(vax) || defined(tahoe)
4010378Speter # define FORCENAME "r0"
4130032Smckusick #endif vax || tahoe
4210378Speter #ifdef mc68000
4310378Speter # define FORCENAME "d0"
4412968Smckusick # define ADDRTEMP "a0"
4510378Speter #endif mc68000
46926Speter
47926Speter /*
48926Speter * given a tree for a case statement, generate code for it.
49926Speter * this computes the expression into a register,
50926Speter * puts down the code for each of the cases,
51926Speter * and then decides how to do the case switching.
52763Speter * tcase [0] T_CASE
53763Speter * [1] lineof "case"
54763Speter * [2] expression
55926Speter * [3] list of cased statements:
56763Speter * cstat [0] T_CSTAT
57763Speter * [1] lineof ":"
58926Speter * [2] list of constant labels
59763Speter * [3] statement
60763Speter */
pccaseop(tcase)61763Speter pccaseop( tcase )
6215936Smckusick WHI_CAS *tcase;
63926Speter {
64926Speter struct nl *exprtype;
653830Speter struct nl *exprnlp;
66926Speter struct nl *rangetype;
67926Speter long low;
68926Speter long high;
69926Speter long exprctype;
7015936Smckusick char *swlabel;
7115936Smckusick char *endlabel;
7215936Smckusick char *label;
7315936Smckusick int count;
7415936Smckusick struct tnode *cstatlp;
7515936Smckusick struct tnode *cstatp;
7615936Smckusick struct tnode *casep;
77926Speter struct ct *ctab;
78926Speter struct ct *ctp;
7915936Smckusick bool nr;
80926Speter long goc;
81926Speter int casecmp();
821278Speter bool dupcases;
83763Speter
84926Speter goc = gocnt;
85926Speter /*
86926Speter * find out the type of the case expression
87926Speter * even if the expression has errors (exprtype == NIL), continue.
88926Speter */
8915936Smckusick line = tcase->line_no;
903641Speter codeoff();
9115936Smckusick exprtype = rvalue( tcase->expr , NLNIL , RREQ );
923641Speter codeon();
9315936Smckusick if ( exprtype != NLNIL ) {
94926Speter if ( isnta( exprtype , "bcsi" ) ) {
95926Speter error("Case selectors cannot be %ss" , nameof( exprtype ) );
9615936Smckusick exprtype = NLNIL;
97926Speter } else {
98926Speter if ( exprtype -> class != RANGE ) {
99926Speter rangetype = exprtype -> type;
100926Speter } else {
101926Speter rangetype = exprtype;
102926Speter }
10315936Smckusick if ( rangetype == NLNIL ) {
10415936Smckusick exprtype = NLNIL;
105763Speter } else {
106926Speter low = rangetype -> range[0];
107926Speter high = rangetype -> range[1];
108763Speter }
109763Speter }
110926Speter }
11115936Smckusick if ( exprtype != NLNIL ) {
112763Speter /*
1133641Speter * compute and save the case expression.
1143641Speter * also, put expression into a register
115926Speter * save its c-type and jump to the code to do the switch.
116763Speter */
1173641Speter exprctype = p2type( exprtype );
11815936Smckusick exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG );
11915936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
12018463Sralph exprnlp -> extra_flags , PCCT_INT );
12115936Smckusick (void) rvalue( tcase->expr , NLNIL , RREQ );
12218463Sralph sconv((int) exprctype, (int) PCCT_INT);
12318463Sralph putop( PCC_ASSIGN , PCCT_INT );
12418463Sralph putop( PCC_FORCE , PCCT_INT );
125926Speter putdot( filename , line );
126926Speter swlabel = getlab();
12715936Smckusick putjbr( (long) swlabel );
128926Speter }
129926Speter /*
130926Speter * count the number of cases
131926Speter * and allocate table for cases, lines, and labels
132926Speter * default case goes in ctab[0].
133926Speter */
134926Speter count = 1;
13515936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ;
13615936Smckusick cstatlp = cstatlp->list_node.next ) {
13715936Smckusick cstatp = cstatlp->list_node.list;
13815936Smckusick if ( cstatp == TR_NIL ) {
139926Speter continue;
140763Speter }
14115936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ;
14215936Smckusick casep = casep->list_node.next ) {
143926Speter count++;
144763Speter }
145926Speter }
146926Speter /*
147926Speter */
148926Speter ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
149926Speter if ( ctab == (struct ct *) 0 ) {
150926Speter error("Ran out of memory (case)");
151926Speter pexit( DIED );
152926Speter }
153926Speter /*
154926Speter * pick up default label and label for after case statement.
155926Speter */
15615936Smckusick ctab[0].clabel = (int) getlab();
157926Speter endlabel = getlab();
158926Speter /*
159926Speter * generate code for each case
160926Speter * filling in ctab for each.
161926Speter * nr is for error if no case falls out bottom.
162926Speter */
16315936Smckusick nr = TRUE;;
164926Speter count = 0;
16515936Smckusick for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ;
16615936Smckusick cstatlp = cstatlp->list_node.next ) {
16715936Smckusick cstatp = cstatlp->list_node.list;
16815936Smckusick if ( cstatp == TR_NIL ) {
169926Speter continue;
170926Speter }
17115936Smckusick line = cstatp->c_stmnt.line_no;
172926Speter label = getlab();
17315936Smckusick for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ;
17415936Smckusick casep = casep->list_node.next ) {
17515936Smckusick gconst( casep->list_node.list );
17615936Smckusick if( exprtype == NLNIL || con.ctype == NIL ) {
177763Speter continue;
178763Speter }
17915936Smckusick if ( incompat( con.ctype , exprtype , TR_NIL ) ) {
180926Speter cerror("Case label type clashed with case selector expression type");
181926Speter continue;
182763Speter }
183926Speter if ( con.crval < low || con.crval > high ) {
184926Speter error("Case label out of range");
185926Speter continue;
186763Speter }
187926Speter count++;
188926Speter ctab[ count ].cconst = con.crval;
189926Speter ctab[ count ].cline = line;
19015936Smckusick ctab[ count ].clabel = (int) label;
191763Speter }
192763Speter /*
193926Speter * put out the statement
194763Speter */
19515936Smckusick (void) putlab( label );
196926Speter putcnt();
197926Speter level++;
19815936Smckusick statement( cstatp->c_stmnt.stmnt );
19915936Smckusick nr = (nr && noreach)?TRUE:FALSE;
20015936Smckusick noreach = FALSE;
201926Speter level--;
202926Speter if (gotos[cbn]) {
203926Speter ungoto();
204763Speter }
20515936Smckusick putjbr( (long) endlabel );
206763Speter }
2071278Speter noreach = nr;
208926Speter /*
209926Speter * default action is to call error
210926Speter */
21115936Smckusick (void) putlab( (char *) ctab[0].clabel );
21218463Sralph putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) , "_CASERNG" );
21315936Smckusick putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
21418463Sralph exprnlp -> extra_flags , PCCT_INT );
21518463Sralph putop( PCC_CALL , PCCT_INT );
216926Speter putdot( filename , line );
217926Speter /*
218926Speter * sort the cases
219926Speter */
220926Speter qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
221926Speter /*
222926Speter * check for duplicates
223926Speter */
2241278Speter dupcases = FALSE;
225926Speter for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
226926Speter if ( ctp[0].cconst == ctp[1].cconst ) {
2271278Speter error("Multiply defined label in case, lines %d and %d" ,
22815936Smckusick (char *) ctp[0].cline , (char *) ctp[1].cline );
2291278Speter dupcases = TRUE;
230926Speter }
231926Speter }
2321278Speter if ( dupcases ) {
2331278Speter return;
2341278Speter }
235926Speter /*
236926Speter * choose a switch algorithm and implement it:
237926Speter * direct switch >= 1/3 full and >= 4 cases.
238926Speter * binary switch not direct switch and > 8 cases.
239926Speter * ifthenelse not direct or binary switch.
240926Speter */
24115936Smckusick (void) putlab( swlabel );
242926Speter if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
243926Speter directsw( ctab , count );
244926Speter } else if ( count > 8 ) {
245926Speter binarysw( ctab , count );
246926Speter } else {
247926Speter itesw( ctab , count );
248926Speter }
24915936Smckusick (void) putlab( endlabel );
250926Speter if ( goc != gocnt ) {
251926Speter putcnt();
252926Speter }
253926Speter }
254763Speter
255926Speter /*
256926Speter * direct switch
257926Speter */
258926Speter directsw( ctab , count )
259926Speter struct ct *ctab;
260926Speter int count;
261926Speter {
26215936Smckusick int fromlabel = (int) getlab();
263926Speter long i;
264926Speter long j;
265926Speter
26610378Speter # ifdef vax
26712968Smckusick if (opt('J')) {
26810378Speter /*
26912968Smckusick * We have a table of absolute addresses.
27012968Smckusick *
27112968Smckusick * subl2 to make r0 a 0-origin byte offset.
27210378Speter * cmpl check against upper limit.
27317425Smckusick * jlssu error if out of bounds.
27412968Smckusick * ashl to make r0 a 0-origin long offset,
27510378Speter * jmp and indirect through it.
27610378Speter */
27715936Smckusick putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME);
27812968Smckusick putprintf(" cmpl $%d,%s", 0,
27915936Smckusick (int) (ctab[count].cconst - ctab[1].cconst),
28015936Smckusick (int) FORCENAME);
28117425Smckusick putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel);
28215936Smckusick putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME);
28312968Smckusick putprintf(" jmp *%s%d(%s)", 0,
28415936Smckusick (int) LABELPREFIX, fromlabel, (int) FORCENAME);
28512968Smckusick } else {
28612968Smckusick /*
28712968Smckusick * We can use the VAX casel instruction with a table
28812968Smckusick * of short relative offsets.
28912968Smckusick */
29015936Smckusick putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME ,
29115936Smckusick (int) ctab[1].cconst ,
29215936Smckusick (int) (ctab[ count ].cconst - ctab[1].cconst ));
29312968Smckusick }
29412968Smckusick # endif vax
29530032Smckusick
29630032Smckusick # ifdef tahoe
29730032Smckusick if (opt('J')) {
29830032Smckusick /*
29930032Smckusick * We have a table of absolute addresses.
30030032Smckusick *
30130032Smckusick * subl2 to make r0 a 0-origin byte offset.
30230032Smckusick * cmpl check against upper limit.
30330032Smckusick * jlssu error if out of bounds.
30430032Smckusick * shal to make r0 a 0-origin long offset,
30530032Smckusick * jmp and indirect through it.
30630032Smckusick */
30730032Smckusick putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME);
30830032Smckusick putprintf(" cmpl $%d,%s", 0,
30930032Smckusick (int) (ctab[count].cconst - ctab[1].cconst),
31030032Smckusick (int) FORCENAME);
31130032Smckusick putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel);
31230032Smckusick putprintf(" shal $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME);
31330032Smckusick putprintf(" jmp *%s%d(%s)", 0,
31430032Smckusick (int) LABELPREFIX, fromlabel, (int) FORCENAME);
31530032Smckusick } else {
31630032Smckusick /*
31730032Smckusick * We can use the TAHOE casel instruction with a table
31830032Smckusick * of short relative offsets.
31930032Smckusick */
32030032Smckusick putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME ,
32130032Smckusick (int) ctab[1].cconst ,
32230032Smckusick (int) (ctab[ count ].cconst - ctab[1].cconst ));
32330032Smckusick putprintf(" .align 1", 0);
32430032Smckusick }
32530032Smckusick # endif tahoe
32630032Smckusick
32712968Smckusick # ifdef mc68000
32812968Smckusick /*
32912968Smckusick * subl to make d0 a 0-origin byte offset.
33012968Smckusick * cmpl check against upper limit.
33112968Smckusick * bhi error if out of bounds.
33212968Smckusick */
33310378Speter putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME);
33410378Speter putprintf(" cmpl #%d,%s", 0,
33510378Speter ctab[count].cconst - ctab[1].cconst, FORCENAME);
33610378Speter putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel);
33712968Smckusick if (opt('J')) {
33812968Smckusick /*
33912968Smckusick * We have a table of absolute addresses.
34012968Smckusick *
34112968Smckusick * asll to make d0 a 0-origin long offset.
34212968Smckusick * movl pick up a jump-table entry
34312968Smckusick * jmp and indirect through it.
34412968Smckusick */
34512968Smckusick putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME);
34612968Smckusick putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP);
34712968Smckusick putprintf(" jmp %s@", 0, ADDRTEMP);
34812968Smckusick } else {
34912968Smckusick /*
35012968Smckusick * We have a table of relative addresses.
35112968Smckusick *
35212968Smckusick * addw to make d0 a 0-origin word offset.
35312968Smckusick * movw pick up a jump-table entry
35412968Smckusick * jmp and indirect through it.
35512968Smckusick */
35612968Smckusick putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME);
35712968Smckusick putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
35812968Smckusick putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME);
35912968Smckusick }
36010378Speter # endif mc68000
36115936Smckusick (void) putlab( (char *) fromlabel );
362926Speter i = 1;
363926Speter j = ctab[1].cconst;
364926Speter while ( i <= count ) {
365926Speter if ( j == ctab[ i ].cconst ) {
36612968Smckusick if (opt('J')) {
36712968Smckusick putprintf( " .long " , 1 );
36815936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel );
36912968Smckusick } else {
37012968Smckusick putprintf( " .word " , 1 );
37115936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel );
37212968Smckusick putprintf( "-" , 1 );
37315936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
37412968Smckusick }
375926Speter i++;
376926Speter } else {
37712968Smckusick if (opt('J')) {
37812968Smckusick putprintf( " .long " , 1 );
37915936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel );
38012968Smckusick } else {
38112968Smckusick putprintf( " .word " , 1 );
38215936Smckusick putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel );
38312968Smckusick putprintf( "-" , 1 );
38415936Smckusick putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
38512968Smckusick }
386926Speter }
387926Speter j++;
388926Speter }
38930032Smckusick # if defined(vax) || defined(tahoe)
39010378Speter /*
39110378Speter * execution continues here if value not in range of case.
39210378Speter */
39312968Smckusick if (!opt('J'))
39415936Smckusick putjbr( (long) ctab[0].clabel );
39530032Smckusick # endif vax || tahoe
396926Speter }
397926Speter
398926Speter /*
399926Speter * binary switch
400926Speter * special case out default label and start recursion.
401926Speter */
402926Speter binarysw( ctab , count )
403926Speter struct ct *ctab;
404926Speter int count;
405926Speter {
406926Speter
407926Speter bsrecur( ctab[0].clabel , &ctab[0] , count );
408926Speter }
409926Speter
410926Speter /*
411926Speter * recursive log( count ) search.
412926Speter */
bsrecur(deflabel,ctab,count)413926Speter bsrecur( deflabel , ctab , count )
414926Speter int deflabel;
415926Speter struct ct *ctab;
416926Speter int count;
417926Speter {
418926Speter
419926Speter if ( count <= 0 ) {
42015936Smckusick putjbr((long) deflabel);
421926Speter return;
422926Speter } else if ( count == 1 ) {
42330032Smckusick # if defined(vax) || defined(tahoe)
42415936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst);
42515936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel);
42615936Smckusick putjbr((long) deflabel);
42730032Smckusick # endif vax || tahoe
42810378Speter # ifdef mc68000
42915936Smckusick putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME);
43015936Smckusick putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel);
43115936Smckusick putjbr((long) deflabel);
43210378Speter # endif mc68000
433926Speter return;
434926Speter } else {
435926Speter int half = ( count + 1 ) / 2;
43615936Smckusick int gtrlabel = (int) getlab();
437926Speter
43830032Smckusick # if defined(vax) || defined(tahoe)
43915936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst);
44015936Smckusick putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel);
44115936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
44230032Smckusick # endif vax || tahoe
44310378Speter # ifdef mc68000
44415936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME);
44515936Smckusick putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel);
44615936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
44710378Speter # endif mc68000
448926Speter bsrecur( deflabel , &ctab[0] , half - 1 );
44915936Smckusick (void) putlab((char *) gtrlabel);
450926Speter bsrecur( deflabel , &ctab[ half ] , count - half );
451926Speter return;
452926Speter }
453926Speter }
454926Speter
455926Speter itesw( ctab , count )
456926Speter struct ct *ctab;
457926Speter int count;
458926Speter {
459926Speter int i;
460926Speter
461926Speter for ( i = 1 ; i <= count ; i++ ) {
46230032Smckusick # if defined(vax) || defined(tahoe)
46315936Smckusick putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst);
46415936Smckusick putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
46530032Smckusick # endif vax || tahoe
46610378Speter # ifdef mc68000
46715936Smckusick putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME);
46815936Smckusick putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
46910378Speter # endif mc68000
470926Speter }
47115936Smckusick putjbr((long) ctab[0].clabel);
472926Speter return;
473926Speter }
474926Speter int
casecmp(this,that)475926Speter casecmp( this , that )
476926Speter struct ct *this;
477926Speter struct ct *that;
478926Speter {
479926Speter if ( this -> cconst < that -> cconst ) {
480926Speter return -1;
481926Speter } else if ( this -> cconst > that -> cconst ) {
482926Speter return 1;
483926Speter } else {
484926Speter return 0;
485926Speter }
486926Speter }
487763Speter #endif PC
488