new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / pascal / src / pccaseop.c
CommitLineData
0fc6e47b
KB
1/*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.redist.c%
252367af 6 */
c0d4f538 7
845d7457 8#ifndef lint
0fc6e47b
KB
9static char sccsid[] = "@(#)pccaseop.c 5.3 (Berkeley) %G%";
10#endif /* not lint */
c0d4f538
PK
11
12#include "whoami.h"
13#ifdef PC
14 /*
15 * and the rest of the file
16 */
17#include "0.h"
18#include "tree.h"
19#include "objfmt.h"
c60bfb0d 20#include <pcc.h>
c0d4f538 21#include "pc.h"
f763caa4 22#include "tmps.h"
845d7457 23#include "tree_ty.h"
85aa76bb
PK
24
25 /*
26 * structure for a case:
27 * its constant label, line number (for errors), and location label.
28 */
29struct ct {
30 long cconst;
31 int cline;
32 int clabel;
33};
34
c0d4f538 35 /*
c60bfb0d 36 * the PCC_FORCE operator puts its operand into a register.
85aa76bb
PK
37 * these to keep from thinking of it as r0 all over.
38 */
fe8ff1f7 39#if defined(vax) || defined(tahoe)
79be1732 40# define FORCENAME "r0"
fe8ff1f7 41#endif vax || tahoe
79be1732
PK
42#ifdef mc68000
43# define FORCENAME "d0"
b6f7349b 44# define ADDRTEMP "a0"
79be1732 45#endif mc68000
85aa76bb
PK
46
47 /*
48 * given a tree for a case statement, generate code for it.
49 * this computes the expression into a register,
50 * puts down the code for each of the cases,
51 * and then decides how to do the case switching.
c0d4f538
PK
52 * tcase [0] T_CASE
53 * [1] lineof "case"
54 * [2] expression
85aa76bb 55 * [3] list of cased statements:
c0d4f538
PK
56 * cstat [0] T_CSTAT
57 * [1] lineof ":"
85aa76bb 58 * [2] list of constant labels
c0d4f538
PK
59 * [3] statement
60 */
c0d4f538 61pccaseop( tcase )
845d7457 62 WHI_CAS *tcase;
85aa76bb
PK
63{
64 struct nl *exprtype;
1f43951f 65 struct nl *exprnlp;
85aa76bb
PK
66 struct nl *rangetype;
67 long low;
68 long high;
69 long exprctype;
845d7457
KM
70 char *swlabel;
71 char *endlabel;
72 char *label;
73 int count;
74 struct tnode *cstatlp;
75 struct tnode *cstatp;
76 struct tnode *casep;
85aa76bb
PK
77 struct ct *ctab;
78 struct ct *ctp;
845d7457 79 bool nr;
85aa76bb
PK
80 long goc;
81 int casecmp();
14ac8121 82 bool dupcases;
c0d4f538 83
85aa76bb
PK
84 goc = gocnt;
85 /*
86 * find out the type of the case expression
87 * even if the expression has errors (exprtype == NIL), continue.
88 */
845d7457 89 line = tcase->line_no;
1a571904 90 codeoff();
845d7457 91 exprtype = rvalue( tcase->expr , NLNIL , RREQ );
1a571904 92 codeon();
845d7457 93 if ( exprtype != NLNIL ) {
85aa76bb
PK
94 if ( isnta( exprtype , "bcsi" ) ) {
95 error("Case selectors cannot be %ss" , nameof( exprtype ) );
845d7457 96 exprtype = NLNIL;
85aa76bb
PK
97 } else {
98 if ( exprtype -> class != RANGE ) {
99 rangetype = exprtype -> type;
c0d4f538 100 } else {
85aa76bb 101 rangetype = exprtype;
c0d4f538 102 }
845d7457
KM
103 if ( rangetype == NLNIL ) {
104 exprtype = NLNIL;
85aa76bb
PK
105 } else {
106 low = rangetype -> range[0];
107 high = rangetype -> range[1];
c0d4f538 108 }
c0d4f538 109 }
85aa76bb 110 }
845d7457 111 if ( exprtype != NLNIL ) {
c0d4f538 112 /*
1a571904
PK
113 * compute and save the case expression.
114 * also, put expression into a register
85aa76bb 115 * save its c-type and jump to the code to do the switch.
c0d4f538 116 */
1a571904 117 exprctype = p2type( exprtype );
845d7457
KM
118 exprnlp = tmpalloc( (long) (sizeof (long)), nl + T4INT , NOREG );
119 putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
c60bfb0d 120 exprnlp -> extra_flags , PCCT_INT );
845d7457 121 (void) rvalue( tcase->expr , NLNIL , RREQ );
c60bfb0d
RC
122 sconv((int) exprctype, (int) PCCT_INT);
123 putop( PCC_ASSIGN , PCCT_INT );
124 putop( PCC_FORCE , PCCT_INT );
85aa76bb 125 putdot( filename , line );
85aa76bb 126 swlabel = getlab();
845d7457 127 putjbr( (long) swlabel );
85aa76bb
PK
128 }
129 /*
130 * count the number of cases
131 * and allocate table for cases, lines, and labels
132 * default case goes in ctab[0].
133 */
134 count = 1;
845d7457
KM
135 for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ;
136 cstatlp = cstatlp->list_node.next ) {
137 cstatp = cstatlp->list_node.list;
138 if ( cstatp == TR_NIL ) {
85aa76bb 139 continue;
c0d4f538 140 }
845d7457
KM
141 for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ;
142 casep = casep->list_node.next ) {
85aa76bb 143 count++;
c0d4f538 144 }
85aa76bb
PK
145 }
146 /*
147 */
148 ctab = (struct ct *) malloc( count * sizeof( struct ct ) );
149 if ( ctab == (struct ct *) 0 ) {
150 error("Ran out of memory (case)");
151 pexit( DIED );
152 }
153 /*
154 * pick up default label and label for after case statement.
155 */
845d7457 156 ctab[0].clabel = (int) getlab();
85aa76bb
PK
157 endlabel = getlab();
158 /*
159 * generate code for each case
160 * filling in ctab for each.
161 * nr is for error if no case falls out bottom.
162 */
845d7457 163 nr = TRUE;;
85aa76bb 164 count = 0;
845d7457
KM
165 for ( cstatlp = tcase->stmnt_list ; cstatlp != TR_NIL ;
166 cstatlp = cstatlp->list_node.next ) {
167 cstatp = cstatlp->list_node.list;
168 if ( cstatp == TR_NIL ) {
85aa76bb
PK
169 continue;
170 }
845d7457 171 line = cstatp->c_stmnt.line_no;
85aa76bb 172 label = getlab();
845d7457
KM
173 for ( casep = cstatp->c_stmnt.const_list ; casep != TR_NIL ;
174 casep = casep->list_node.next ) {
175 gconst( casep->list_node.list );
176 if( exprtype == NLNIL || con.ctype == NIL ) {
c0d4f538
PK
177 continue;
178 }
845d7457 179 if ( incompat( con.ctype , exprtype , TR_NIL ) ) {
85aa76bb
PK
180 cerror("Case label type clashed with case selector expression type");
181 continue;
c0d4f538 182 }
85aa76bb
PK
183 if ( con.crval < low || con.crval > high ) {
184 error("Case label out of range");
185 continue;
c0d4f538 186 }
85aa76bb
PK
187 count++;
188 ctab[ count ].cconst = con.crval;
189 ctab[ count ].cline = line;
845d7457 190 ctab[ count ].clabel = (int) label;
c0d4f538
PK
191 }
192 /*
85aa76bb 193 * put out the statement
c0d4f538 194 */
845d7457 195 (void) putlab( label );
85aa76bb
PK
196 putcnt();
197 level++;
845d7457
KM
198 statement( cstatp->c_stmnt.stmnt );
199 nr = (nr && noreach)?TRUE:FALSE;
200 noreach = FALSE;
85aa76bb
PK
201 level--;
202 if (gotos[cbn]) {
203 ungoto();
204 }
845d7457 205 putjbr( (long) endlabel );
85aa76bb 206 }
14ac8121 207 noreach = nr;
85aa76bb
PK
208 /*
209 * default action is to call error
210 */
845d7457 211 (void) putlab( (char *) ctab[0].clabel );
c60bfb0d 212 putleaf( PCC_ICON , 0 , 0 , PCCM_ADDTYPE( PCCTM_FTN | PCCT_INT , PCCTM_PTR ) , "_CASERNG" );
845d7457 213 putRV((char *) 0 , cbn , exprnlp -> value[ NL_OFFS ] ,
c60bfb0d
RC
214 exprnlp -> extra_flags , PCCT_INT );
215 putop( PCC_CALL , PCCT_INT );
85aa76bb
PK
216 putdot( filename , line );
217 /*
218 * sort the cases
219 */
220 qsort( &ctab[1] , count , sizeof (struct ct) , casecmp );
221 /*
222 * check for duplicates
223 */
14ac8121 224 dupcases = FALSE;
85aa76bb
PK
225 for ( ctp = &ctab[1] ; ctp < &ctab[ count ] ; ctp++ ) {
226 if ( ctp[0].cconst == ctp[1].cconst ) {
14ac8121 227 error("Multiply defined label in case, lines %d and %d" ,
845d7457 228 (char *) ctp[0].cline , (char *) ctp[1].cline );
14ac8121 229 dupcases = TRUE;
c0d4f538 230 }
14ac8121
PK
231 }
232 if ( dupcases ) {
233 return;
c0d4f538 234 }
85aa76bb
PK
235 /*
236 * choose a switch algorithm and implement it:
237 * direct switch >= 1/3 full and >= 4 cases.
238 * binary switch not direct switch and > 8 cases.
239 * ifthenelse not direct or binary switch.
240 */
845d7457 241 (void) putlab( swlabel );
85aa76bb
PK
242 if ( ctab[ count ].cconst - ctab[1].cconst < 3 * count && count >= 4 ) {
243 directsw( ctab , count );
244 } else if ( count > 8 ) {
245 binarysw( ctab , count );
246 } else {
247 itesw( ctab , count );
248 }
845d7457 249 (void) putlab( endlabel );
85aa76bb
PK
250 if ( goc != gocnt ) {
251 putcnt();
252 }
253}
c0d4f538 254
85aa76bb
PK
255 /*
256 * direct switch
257 */
258directsw( ctab , count )
259 struct ct *ctab;
260 int count;
261{
845d7457 262 int fromlabel = (int) getlab();
85aa76bb
PK
263 long i;
264 long j;
265
79be1732 266# ifdef vax
b6f7349b 267 if (opt('J')) {
79be1732 268 /*
b6f7349b
KM
269 * We have a table of absolute addresses.
270 *
271 * subl2 to make r0 a 0-origin byte offset.
79be1732 272 * cmpl check against upper limit.
2ca7c6cb 273 * jlssu error if out of bounds.
b6f7349b 274 * ashl to make r0 a 0-origin long offset,
79be1732
PK
275 * jmp and indirect through it.
276 */
845d7457 277 putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME);
b6f7349b 278 putprintf(" cmpl $%d,%s", 0,
845d7457
KM
279 (int) (ctab[count].cconst - ctab[1].cconst),
280 (int) FORCENAME);
2ca7c6cb 281 putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel);
845d7457 282 putprintf(" ashl $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME);
b6f7349b 283 putprintf(" jmp *%s%d(%s)", 0,
845d7457 284 (int) LABELPREFIX, fromlabel, (int) FORCENAME);
b6f7349b
KM
285 } else {
286 /*
287 * We can use the VAX casel instruction with a table
288 * of short relative offsets.
289 */
845d7457
KM
290 putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME ,
291 (int) ctab[1].cconst ,
292 (int) (ctab[ count ].cconst - ctab[1].cconst ));
b6f7349b
KM
293 }
294# endif vax
fe8ff1f7
KM
295
296# ifdef tahoe
297 if (opt('J')) {
298 /*
299 * We have a table of absolute addresses.
300 *
301 * subl2 to make r0 a 0-origin byte offset.
302 * cmpl check against upper limit.
303 * jlssu error if out of bounds.
304 * shal to make r0 a 0-origin long offset,
305 * jmp and indirect through it.
306 */
307 putprintf(" subl2 $%d,%s", 0, (int) ctab[1].cconst, (int) FORCENAME);
308 putprintf(" cmpl $%d,%s", 0,
309 (int) (ctab[count].cconst - ctab[1].cconst),
310 (int) FORCENAME);
311 putprintf(" jlssu %s%d", 0, (int) LABELPREFIX, ctab[0].clabel);
312 putprintf(" shal $2,%s,%s", 0, (int) FORCENAME, (int) FORCENAME);
313 putprintf(" jmp *%s%d(%s)", 0,
314 (int) LABELPREFIX, fromlabel, (int) FORCENAME);
315 } else {
316 /*
317 * We can use the TAHOE casel instruction with a table
318 * of short relative offsets.
319 */
320 putprintf(" casel %s,$%d,$%d" , 0 , (int) FORCENAME ,
321 (int) ctab[1].cconst ,
322 (int) (ctab[ count ].cconst - ctab[1].cconst ));
323 putprintf(" .align 1", 0);
324 }
325# endif tahoe
326
b6f7349b
KM
327# ifdef mc68000
328 /*
329 * subl to make d0 a 0-origin byte offset.
330 * cmpl check against upper limit.
331 * bhi error if out of bounds.
332 */
79be1732
PK
333 putprintf(" subl #%d,%s", 0, ctab[1].cconst, FORCENAME);
334 putprintf(" cmpl #%d,%s", 0,
335 ctab[count].cconst - ctab[1].cconst, FORCENAME);
336 putprintf(" bhi %s%d", 0, LABELPREFIX, ctab[0].clabel);
b6f7349b
KM
337 if (opt('J')) {
338 /*
339 * We have a table of absolute addresses.
340 *
341 * asll to make d0 a 0-origin long offset.
342 * movl pick up a jump-table entry
343 * jmp and indirect through it.
344 */
345 putprintf(" asll #2,%s", 0, FORCENAME, FORCENAME);
346 putprintf(" movl pc@(4,%s:l),%s", 0, FORCENAME, ADDRTEMP);
347 putprintf(" jmp %s@", 0, ADDRTEMP);
348 } else {
349 /*
350 * We have a table of relative addresses.
351 *
352 * addw to make d0 a 0-origin word offset.
353 * movw pick up a jump-table entry
354 * jmp and indirect through it.
355 */
356 putprintf(" addw %s,%s", 0, FORCENAME, FORCENAME);
357 putprintf(" movw pc@(6,%s:w),%s", 0, FORCENAME, FORCENAME);
358 putprintf(" jmp pc@(2,%s:w)", 0, FORCENAME);
359 }
79be1732 360# endif mc68000
845d7457 361 (void) putlab( (char *) fromlabel );
85aa76bb
PK
362 i = 1;
363 j = ctab[1].cconst;
364 while ( i <= count ) {
365 if ( j == ctab[ i ].cconst ) {
b6f7349b
KM
366 if (opt('J')) {
367 putprintf( " .long " , 1 );
845d7457 368 putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ i ].clabel );
b6f7349b
KM
369 } else {
370 putprintf( " .word " , 1 );
845d7457 371 putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ i ].clabel );
b6f7349b 372 putprintf( "-" , 1 );
845d7457 373 putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
b6f7349b 374 }
85aa76bb
PK
375 i++;
376 } else {
b6f7349b
KM
377 if (opt('J')) {
378 putprintf( " .long " , 1 );
845d7457 379 putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , ctab[ 0 ].clabel );
b6f7349b
KM
380 } else {
381 putprintf( " .word " , 1 );
845d7457 382 putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , ctab[ 0 ].clabel );
b6f7349b 383 putprintf( "-" , 1 );
845d7457 384 putprintf( PREFIXFORMAT , 0 , (int) LABELPREFIX , fromlabel );
b6f7349b 385 }
85aa76bb
PK
386 }
387 j++;
388 }
fe8ff1f7 389# if defined(vax) || defined(tahoe)
79be1732
PK
390 /*
391 * execution continues here if value not in range of case.
392 */
b6f7349b 393 if (!opt('J'))
845d7457 394 putjbr( (long) ctab[0].clabel );
fe8ff1f7 395# endif vax || tahoe
85aa76bb
PK
396}
397
398 /*
399 * binary switch
400 * special case out default label and start recursion.
401 */
402binarysw( ctab , count )
403 struct ct *ctab;
404 int count;
405{
406
407 bsrecur( ctab[0].clabel , &ctab[0] , count );
408}
409
410 /*
411 * recursive log( count ) search.
412 */
413bsrecur( deflabel , ctab , count )
414 int deflabel;
415 struct ct *ctab;
416 int count;
417{
418
419 if ( count <= 0 ) {
845d7457 420 putjbr((long) deflabel);
85aa76bb
PK
421 return;
422 } else if ( count == 1 ) {
fe8ff1f7 423# if defined(vax) || defined(tahoe)
845d7457
KM
424 putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[1].cconst);
425 putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[1].clabel);
426 putjbr((long) deflabel);
fe8ff1f7 427# endif vax || tahoe
79be1732 428# ifdef mc68000
845d7457
KM
429 putprintf(" cmpl #%d,%s", 0, ctab[1].cconst, (int) FORCENAME);
430 putprintf(" jeq L%d", 0, (int) LABELPREFIX, ctab[1].clabel);
431 putjbr((long) deflabel);
79be1732 432# endif mc68000
85aa76bb
PK
433 return;
434 } else {
435 int half = ( count + 1 ) / 2;
845d7457 436 int gtrlabel = (int) getlab();
85aa76bb 437
fe8ff1f7 438# if defined(vax) || defined(tahoe)
845d7457
KM
439 putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[half].cconst);
440 putprintf(" jgtr %s%d", 0, (int) LABELPREFIX, gtrlabel);
441 putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
fe8ff1f7 442# endif vax || tahoe
79be1732 443# ifdef mc68000
845d7457
KM
444 putprintf(" cmpl #%d,%s", 0, (int) ctab[half].cconst, (int) FORCENAME);
445 putprintf(" jgt %s%d", 0, (int) LABELPREFIX, gtrlabel);
446 putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[half].clabel);
79be1732 447# endif mc68000
85aa76bb 448 bsrecur( deflabel , &ctab[0] , half - 1 );
845d7457 449 (void) putlab((char *) gtrlabel);
85aa76bb
PK
450 bsrecur( deflabel , &ctab[ half ] , count - half );
451 return;
452 }
453}
454
455itesw( ctab , count )
456 struct ct *ctab;
457 int count;
458{
459 int i;
460
461 for ( i = 1 ; i <= count ; i++ ) {
fe8ff1f7 462# if defined(vax) || defined(tahoe)
845d7457
KM
463 putprintf(" cmpl %s,$%d", 0, (int) FORCENAME, (int) ctab[i].cconst);
464 putprintf(" jeql %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
fe8ff1f7 465# endif vax || tahoe
79be1732 466# ifdef mc68000
845d7457
KM
467 putprintf(" cmpl #%d,%s", 0, (int) ctab[i].cconst, (int) FORCENAME);
468 putprintf(" jeq %s%d", 0, (int) LABELPREFIX, ctab[i].clabel);
79be1732 469# endif mc68000
85aa76bb 470 }
845d7457 471 putjbr((long) ctab[0].clabel);
85aa76bb
PK
472 return;
473}
474int
475casecmp( this , that )
476 struct ct *this;
477 struct ct *that;
478{
479 if ( this -> cconst < that -> cconst ) {
480 return -1;
481 } else if ( this -> cconst > that -> cconst ) {
482 return 1;
483 } else {
484 return 0;
485 }
486}
c0d4f538 487#endif PC