BSD 4 release
[unix-history] / usr / src / cmd / pi / pccaseop.c
CommitLineData
85aa76bb 1/* Copyright (c) 1980 Regents of the University of California */
c0d4f538 2
31cef89c 3static char sccsid[] = "@(#)pccaseop.c 1.4 10/8/80";
c0d4f538
PK
4
5#include "whoami.h"
6#ifdef PC
7 /*
8 * and the rest of the file
9 */
10#include "0.h"
11#include "tree.h"
12#include "objfmt.h"
13#include "pcops.h"
14#include "pc.h"
85aa76bb
PK
15
16 /*
17 * structure for a case:
18 * its constant label, line number (for errors), and location label.
19 */
20struct ct {
21 long cconst;
22 int cline;
23 int clabel;
24};
25
c0d4f538 26 /*
85aa76bb
PK
27 * the P2FORCE operator puts its operand into a register.
28 * these to keep from thinking of it as r0 all over.
29 */
30#define FORCENAME "r0"
31#define FORCENUMBER 0
32
33 /*
34 * given a tree for a case statement, generate code for it.
35 * this computes the expression into a register,
36 * puts down the code for each of the cases,
37 * and then decides how to do the case switching.
c0d4f538
PK
38 * tcase [0] T_CASE
39 * [1] lineof "case"
40 * [2] expression
85aa76bb 41 * [3] list of cased statements:
c0d4f538
PK
42 * cstat [0] T_CSTAT
43 * [1] lineof ":"
85aa76bb 44 * [2] list of constant labels
c0d4f538
PK
45 * [3] statement
46 */
c0d4f538
PK
47pccaseop( tcase )
48 int *tcase;
85aa76bb
PK
49{
50 struct nl *exprtype;
51 struct nl *rangetype;
52 long low;
53 long high;
54 long exprctype;
55 long swlabel;
56 long endlabel;
57 long label;
58 long count;
59 long *cstatlp;
60 long *cstatp;
61 long *casep;
62 struct ct *ctab;
63 struct ct *ctp;
64 long i;
65 long nr;
66 long goc;
67 int casecmp();
14ac8121 68 bool dupcases;
c0d4f538 69
85aa76bb
PK
70 goc = gocnt;
71 /*
72 * find out the type of the case expression
73 * even if the expression has errors (exprtype == NIL), continue.
74 */
75 line = tcase[1];
76 exprtype = rvalue( (int *) tcase[2] , NIL , RREQ );
77 if ( exprtype != NIL ) {
78 if ( isnta( exprtype , "bcsi" ) ) {
79 error("Case selectors cannot be %ss" , nameof( exprtype ) );
80 exprtype = NIL;
81 } else {
82 if ( exprtype -> class != RANGE ) {
83 rangetype = exprtype -> type;
c0d4f538 84 } else {
85aa76bb 85 rangetype = exprtype;
c0d4f538 86 }
85aa76bb
PK
87 if ( rangetype == NIL ) {
88 exprtype = NIL;
89 } else {
90 low = rangetype -> range[0];
91 high = rangetype -> range[1];
c0d4f538 92 }
c0d4f538 93 }
85aa76bb
PK
94 }
95 if ( exprtype != NIL ) {
c0d4f538 96 /*
85aa76bb
PK
97 * put expression into a register
98 * save its c-type and jump to the code to do the switch.
c0d4f538 99 */
85aa76bb
PK
100 putop( P2FORCE , P2INT );
101 putdot( filename , line );
102 exprctype = p2type( exprtype );
103 swlabel = getlab();
104 putjbr( swlabel );
105 }
106 /*
107 * count the number of cases
108 * and allocate table for cases, lines, and labels
109 * default case goes in ctab[0].
110 */
111 count = 1;
112 for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
113 cstatp = cstatlp[1];
114 if ( cstatp == NIL ) {
115 continue;
c0d4f538 116 }
85aa76bb
PK
117 for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
118 count++;
c0d4f538 119 }
85aa76bb
PK
120 }
121 /*
122 */
123 ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
124 if ( ctab == (struct ct *) 0 ) {
125 error("Ran out of memory (case)");
126 pexit( DIED );
127 }
128 /*
129 * pick up default label and label for after case statement.
130 */
131 ctab[0].clabel = getlab();
132 endlabel = getlab();
133 /*
134 * generate code for each case
135 * filling in ctab for each.
136 * nr is for error if no case falls out bottom.
137 */
138 nr = 1;
139 count = 0;
140 for ( cstatlp = tcase[3] ; cstatlp != NIL ; cstatlp = cstatlp[2] ) {
141 cstatp = cstatlp[1];
142 if ( cstatp == NIL ) {
143 continue;
144 }
145 line = cstatp[1];
146 label = getlab();
147 for ( casep = cstatp[2] ; casep != NIL ; casep = casep[2] ) {
148 gconst( casep[1] );
149 if( exprtype == NIL || con.ctype == NIL ) {
c0d4f538
PK
150 continue;
151 }
85aa76bb
PK
152 if ( incompat( con.ctype , exprtype , NIL ) ) {
153 cerror("Case label type clashed with case selector expression type");
154 continue;
c0d4f538 155 }
85aa76bb
PK
156 if ( con.crval < low || con.crval > high ) {
157 error("Case label out of range");
158 continue;
c0d4f538 159 }
85aa76bb
PK
160 count++;
161 ctab[ count ].cconst = con.crval;
162 ctab[ count ].cline = line;
163 ctab[ count ].clabel = label;
c0d4f538
PK
164 }
165 /*
85aa76bb 166 * put out the statement
c0d4f538 167 */
85aa76bb
PK
168 putlab( label );
169 putcnt();
170 level++;
171 statement( cstatp[3] );
172 nr &= noreach;
173 noreach = 0;
174 level--;
175 if (gotos[cbn]) {
176 ungoto();
177 }
178 putjbr( endlabel );
179 }
14ac8121 180 noreach = nr;
85aa76bb
PK
181 /*
182 * default action is to call error
183 */
184 putlab( ctab[0].clabel );
185 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_ERROR" );
186 putleaf( P2ICON , ECASE , 0 , P2INT , 0 );
187 putleaf( P2REG , FORCENUMBER , 0 , P2INT , 0 );
188 putop( P2LISTOP , P2INT );
189 putop( P2CALL , P2INT );
190 putdot( filename , line );
191 /*
192 * sort the cases
193 */
194 qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
195 /*
196 * check for duplicates
197 */
14ac8121 198 dupcases = FALSE;
85aa76bb
PK
199 for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
200 if ( ctp[0].cconst == ctp[1].cconst ) {
14ac8121 201 error("Multiply defined label in case, lines %d and %d" ,
85aa76bb 202 ctp[0].cline , ctp[1].cline );
14ac8121 203 dupcases = TRUE;
c0d4f538 204 }
14ac8121
PK
205 }
206 if ( dupcases ) {
207 return;
c0d4f538 208 }
85aa76bb
PK
209 /*
210 * choose a switch algorithm and implement it:
211 * direct switch >= 1/3 full and >= 4 cases.
212 * binary switch not direct switch and > 8 cases.
213 * ifthenelse not direct or binary switch.
214 */
215 putlab( swlabel );
216 if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
217 directsw( ctab , count );
218 } else if ( count > 8 ) {
219 binarysw( ctab , count );
220 } else {
221 itesw( ctab , count );
222 }
223 putlab( endlabel );
85aa76bb
PK
224 if ( goc != gocnt ) {
225 putcnt();
226 }
227}
c0d4f538 228
85aa76bb
PK
229 /*
230 * direct switch
231 */
232directsw( ctab , count )
233 struct ct *ctab;
234 int count;
235{
236 int fromlabel = getlab();
237 long i;
238 long j;
239
240 putprintf( " casel %s,$%d,$%d" , 0 , FORCENAME ,
241 ctab[1].cconst , ctab[ count ].cconst - ctab[1].cconst );
242 putlab( fromlabel );
243 i = 1;
244 j = ctab[1].cconst;
245 while ( i <= count ) {
246 if ( j == ctab[ i ].cconst ) {
247 putprintf( " .word " , 1 );
248 putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ i ].clabel );
249 putprintf( "-" , 1 );
250 putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
251 i++;
252 } else {
253 putprintf( " .word " , 1 );
254 putprintf( PREFIXFORMAT , 1 , LABELPREFIX , ctab[ 0 ].clabel );
255 putprintf( "-" , 1 );
256 putprintf( PREFIXFORMAT , 0 , LABELPREFIX , fromlabel );
257 }
258 j++;
259 }
260 putjbr( ctab[0].clabel );
261}
262
263 /*
264 * binary switch
265 * special case out default label and start recursion.
266 */
267binarysw( ctab , count )
268 struct ct *ctab;
269 int count;
270{
271
272 bsrecur( ctab[0].clabel , &ctab[0] , count );
273}
274
275 /*
276 * recursive log( count ) search.
277 */
278bsrecur( deflabel , ctab , count )
279 int deflabel;
280 struct ct *ctab;
281 int count;
282{
283
284 if ( count <= 0 ) {
285 putprintf( " jbr L%d" , 0 , deflabel );
286 return;
287 } else if ( count == 1 ) {
288 putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[1].cconst );
289 putprintf( " jeql L%d" , 0 , ctab[1].clabel );
290 putprintf( " jbr L%d" , 0 , deflabel );
291 return;
292 } else {
293 int half = ( count + 1 ) / 2;
294 int gtrlabel = getlab();
295
296 putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ half ].cconst );
85aa76bb 297 putprintf( " jgtr L%d" , 0 , gtrlabel );
9b74e745 298 putprintf( " jeql L%d" , 0 , ctab[ half ].clabel );
85aa76bb
PK
299 bsrecur( deflabel , &ctab[0] , half - 1 );
300 putprintf( "L%d:" , 0 , gtrlabel );
301 bsrecur( deflabel , &ctab[ half ] , count - half );
302 return;
303 }
304}
305
306itesw( ctab , count )
307 struct ct *ctab;
308 int count;
309{
310 int i;
311
312 for ( i = 1 ; i <= count ; i++ ) {
313 putprintf( " cmpl %s,$%d" , 0 , FORCENAME , ctab[ i ].cconst );
314 putprintf( " jeql L%d" , 0 , ctab[ i ].clabel );
315 }
316 putprintf( " jbr L%d" , 0 , ctab[0].clabel );
317 return;
318}
319int
320casecmp( this , that )
321 struct ct *this;
322 struct ct *that;
323{
324 if ( this -> cconst < that -> cconst ) {
325 return -1;
326 } else if ( this -> cconst > that -> cconst ) {
327 return 1;
328 } else {
329 return 0;
330 }
331}
c0d4f538 332#endif PC