BSD 4_4 release
[unix-history] / usr / src / old / pcc / ccom.vax / code.c
CommitLineData
4d89f1ac 1#ifndef lint
ca67e7b4 2static char *sccsid ="@(#)code.c 1.10 (Berkeley) 5/31/88";
4d89f1ac
RC
3#endif lint
4
0ec67d08 5# include "pass1.h"
7c801adb
ML
6# include <sys/types.h>
7# include <a.out.h>
8# include <stab.h>
9
10int proflg = 0; /* are we generating profiling code? */
11int strftn = 0; /* is the current function one which returns a value */
12int gdebug;
13int fdefflag; /* are we within a function definition ? */
72daa130 14#ifndef STABDOT
7c801adb 15char NULLNAME[8];
72daa130 16#endif
7c801adb
ML
17int labelno;
18
88bb0c9f
KM
19# define putstr(s) fputs((s), stdout)
20
7c801adb
ML
21branch( n ){
22 /* output a branch to label n */
23 /* exception is an ordinary function branching to retlab: then, return */
41733f0f 24 if( nerrors ) return;
7c801adb 25 if( n == retlab && !strftn ){
88bb0c9f 26 putstr( " ret\n" );
7c801adb
ML
27 }
28 else printf( " jbr L%d\n", n );
29 }
30
31int lastloc = { -1 };
32
33short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
34#define LOG2SZ 9
35
36defalign(n) {
37 /* cause the alignment to become a multiple of n */
38 n /= SZCHAR;
39 if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
40 }
41
42locctr( l ){
43 register temp;
44 /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
45
46 if( l == lastloc ) return(l);
47 temp = lastloc;
48 lastloc = l;
41733f0f 49 if( nerrors ) return(temp);
7c801adb
ML
50 switch( l ){
51
52 case PROG:
88bb0c9f 53 putstr( " .text\n" );
7c801adb
ML
54 psline();
55 break;
56
57 case DATA:
58 case ADATA:
88bb0c9f 59 putstr( " .data\n" );
7c801adb
ML
60 break;
61
62 case STRNG:
88bb0c9f 63 putstr( " .data 1\n" );
7c801adb
ML
64 break;
65
66 case ISTRNG:
88bb0c9f 67 putstr( " .data 2\n" );
7c801adb
ML
68 break;
69
70 case STAB:
88bb0c9f 71 putstr( " .stab\n" );
7c801adb
ML
72 break;
73
74 default:
75 cerror( "illegal location counter" );
76 }
77
78 return( temp );
79 }
80
81deflab( n ){
82 /* output something to define the current position as label n */
38cb9d5a 83 if (nerrors) return;
7c801adb
ML
84 printf( "L%d:\n", n );
85 }
86
87int crslab = 10;
88
89getlab(){
90 /* return a number usable for a label */
91 return( ++crslab );
92 }
93
94
95int ent_mask[] = {
96 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
97
98int reg_use = 11;
99
100efcode(){
101 /* code for the end of a function */
102
103 if( strftn ){ /* copy output (in R2) to caller */
104 register NODE *l, *r;
105 register struct symtab *p;
106 register TWORD t;
7c801adb
ML
107 int i;
108
109 p = &stab[curftn];
110 t = p->stype;
111 t = DECREF(t);
112
113 deflab( retlab );
114
115 i = getlab(); /* label for return area */
116#ifndef LCOMM
88bb0c9f
KM
117 putstr(" .data\n" );
118 putstr(" .align 2\n" );
7c801adb 119 printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
88bb0c9f 120 putstr(" .text\n" );
7c801adb
ML
121#else
122 { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
e2a25814
DS
123 if (sz % (SZINT/SZCHAR))
124 sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
7c801adb
ML
125 printf(" .lcomm L%d,%d\n", i, sz);
126 }
127#endif
128 psline();
129 printf(" movab L%d,r1\n", i);
130
131 reached = 1;
132 l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
133 l->tn.rval = 1; /* R1 */
134 l->tn.lval = 0; /* no offset */
135 r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
136 r->tn.rval = 0; /* R0 */
137 r->tn.lval = 0;
138 l = buildtree( UNARY MUL, l, NIL );
139 r = buildtree( UNARY MUL, r, NIL );
140 l = buildtree( ASSIGN, l, r );
141 l->in.op = FREE;
142 ecomp( l->in.left );
143 printf( " movab L%d,r0\n", i );
144 /* turn off strftn flag, so return sequence will be generated */
145 strftn = 0;
146 }
147 branch( retlab );
148#ifndef VMS
149 printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] );
150#else
151 printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] );
152 /* KLS kludge, under VMS if you use regs 2-5, you must save them. */
153#endif
154 reg_use = 11;
155 p2bend();
156 fdefflag = 0;
157 }
158
159int ftlab1, ftlab2;
160
161bfcode( a, n ) int a[]; {
162 /* code for the beginning of a function; a is an array of
163 indices in stab for the arguments; n is the number */
164 register i;
165 register temp;
166 register struct symtab *p;
167 int off;
e2a25814 168#ifdef TRUST_REG_CHAR_AND_REG_SHORT
7c801adb 169 char *toreg();
e2a25814 170#endif
7c801adb 171
41733f0f 172 if( nerrors ) return;
72daa130 173 (void) locctr( PROG );
7c801adb 174 p = &stab[curftn];
88bb0c9f 175 putstr( " .align 1\n");
7c801adb
ML
176 defnam( p );
177 temp = p->stype;
178 temp = DECREF(temp);
179 strftn = (temp==STRTY) || (temp==UNIONTY);
180
181 retlab = getlab();
182
183 /* routine prolog */
184
185 printf( " .word L%d\n", ftnno);
7c801adb
ML
186 ftlab1 = getlab();
187 ftlab2 = getlab();
188 printf( " jbr L%d\n", ftlab1);
189 printf( "L%d:\n", ftlab2);
190 if( proflg ) { /* profile code */
191 i = getlab();
192 printf(" movab L%d,r0\n", i);
88bb0c9f
KM
193 putstr(" jsb mcount\n");
194 putstr(" .data\n");
195 putstr(" .align 2\n");
7c801adb 196 printf("L%d: .long 0\n", i);
88bb0c9f 197 putstr(" .text\n");
7c801adb
ML
198 psline();
199 }
200
201 off = ARGINIT;
202
203 for( i=0; i<n; ++i ){
204 p = &stab[a[i]];
205 if( p->sclass == REGISTER ){
206 temp = p->offset; /* save register number */
207 p->sclass = PARAM; /* forget that it is a register */
208 p->offset = NOOFFSET;
72daa130 209 (void) oalloc( p, &off );
e2a25814 210#ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */
7c801adb 211/*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
e2a25814
DS
212#else
213/*tbl*/ printf( " movl %d(ap),r%d\n", p->offset/SZCHAR, temp );
214#endif
7c801adb
ML
215 p->offset = temp; /* remember register number */
216 p->sclass = REGISTER; /* remember that it is a register */
217 }
218 else if( p->stype == STRTY || p->stype == UNIONTY ) {
219 p->offset = NOOFFSET;
220 if( oalloc( p, &off ) ) cerror( "bad argument" );
221 SETOFF( off, ALSTACK );
222 }
223 else {
224 if( oalloc( p, &off ) ) cerror( "bad argument" );
225 }
226
227 }
41733f0f 228 if (gdebug && !nerrors) {
9ad0032c
SL
229#ifdef STABDOT
230 pstabdot(N_SLINE, lineno);
231#else
232 pstab(NULLNAME, N_SLINE);
233 printf("0,%d,LL%d\n", lineno, labelno);
234 printf("LL%d:\n", labelno++);
235#endif
236 }
7c801adb
ML
237 fdefflag = 1;
238 }
239
240bccode(){ /* called just before the first executable statment */
241 /* by now, the automatics and register variables are allocated */
242 SETOFF( autooff, SZINT );
243 /* set aside store area offset */
244 p2bbeg( autooff, regvar );
245 reg_use = (reg_use > regvar ? regvar : reg_use);
246 }
247
cd6b3884 248/*ARGSUSED*/
7c801adb
ML
249ejobcode( flag ){
250 /* called just before final exit */
251 /* flag is 1 if errors, 0 if none */
252 }
253
41733f0f 254#ifndef aobeg
7c801adb
ML
255aobeg(){
256 /* called before removing automatics from stab */
257 }
41733f0f 258#endif aobeg
7c801adb 259
41733f0f 260#ifndef aocode
cd6b3884 261/*ARGSUSED*/
7c801adb
ML
262aocode(p) struct symtab *p; {
263 /* called when automatic p removed from stab */
264 }
41733f0f 265#endif aocode
7c801adb 266
41733f0f 267#ifndef aoend
7c801adb
ML
268aoend(){
269 /* called after removing all automatics from stab */
270 }
41733f0f 271#endif aoend
7c801adb
ML
272
273defnam( p ) register struct symtab *p; {
274 /* define the current location as the name p->sname */
275
276 if( p->sclass == EXTDEF ){
277 printf( " .globl %s\n", exname( p->sname ) );
278 }
279 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
280 else printf( "%s:\n", exname( p->sname ) );
281
282 }
283
284bycode( t, i ){
285#ifdef ASSTRINGS
286static int lastoctal = 0;
287#endif
288
289 /* put byte i+1 in a string */
290
41733f0f 291 if ( nerrors ) return;
7c801adb
ML
292#ifdef ASSTRINGS
293
294 i &= 077;
295 if ( t < 0 ){
88bb0c9f 296 if ( i != 0 ) putstr( "\"\n" );
7c801adb 297 } else {
88bb0c9f 298 if ( i == 0 ) putstr("\t.ascii\t\"");
7c801adb
ML
299 if ( t == '\\' || t == '"'){
300 lastoctal = 0;
301 printf("\\%c", t);
302 }
303 /*
304 * We escape the colon in strings so that
305 * c2 will, in its infinite wisdom, interpret
306 * the characters preceding the colon as a label.
307 * If we didn't escape the colon, c2 would
308 * throw away any trailing blanks or tabs after
309 * the colon, but reconstruct a assembly
310 * language semantically correct program.
311 * C2 hasn't been taught about strings.
312 */
313 else if ( t == ':' || t < 040 || t >= 0177 ){
314 lastoctal++;
315 printf("\\%o",t);
316 }
317 else if ( lastoctal && '0' <= t && t <= '9' ){
318 lastoctal = 0;
319 printf("\"\n\t.ascii\t\"%c", t );
320 }
321 else
322 {
323 lastoctal = 0;
324 putchar(t);
325 }
88bb0c9f 326 if ( i == 077 ) putstr("\"\n");
7c801adb
ML
327 }
328#else
329
330 i &= 07;
331 if( t < 0 ){ /* end of the string */
88bb0c9f 332 if( i != 0 ) putchar( '\n' );
7c801adb
ML
333 }
334
335 else { /* stash byte t into string */
88bb0c9f
KM
336 if( i == 0 ) putstr( " .byte " );
337 else putchar( ',' );
7c801adb 338 printf( "0x%x", t );
88bb0c9f 339 if( i == 07 ) putchar( '\n' );
7c801adb
ML
340 }
341#endif
342 }
343
344zecode( n ){
345 /* n integer words of zeros */
346 OFFSZ temp;
347 if( n <= 0 ) return;
348 printf( " .space %d\n", (SZINT/SZCHAR)*n );
349 temp = n;
350 inoff += temp*SZINT;
351 }
352
cd6b3884 353/*ARGSUSED*/
7c801adb
ML
354fldal( t ) unsigned t; { /* return the alignment of field of type t */
355 uerror( "illegal field type" );
356 return( ALINT );
357 }
358
cd6b3884 359/*ARGSUSED*/
7c801adb
ML
360fldty( p ) struct symtab *p; { /* fix up type of field p */
361 ;
362 }
363
cd6b3884 364/*ARGSUSED*/
7c801adb
ML
365where(c){ /* print location of error */
366 /* c is either 'u', 'c', or 'w' */
367 /* GCOS version */
368 fprintf( stderr, "%s, line %d: ", ftitle, lineno );
369 }
370
371
e2a25814 372#ifdef TRUST_REG_CHAR_AND_REG_SHORT
7c801adb
ML
373/* tbl - toreg() returns a pointer to a char string
374 which is the correct "register move" for the passed type
375 */
376struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
377 {
e2a25814
DS
378 INT, "movl",
379 UNSIGNED, "movl",
380 DOUBLE, "movq",
7c801adb
ML
381 CHAR, "cvtbl",
382 SHORT, "cvtwl",
7c801adb
ML
383 UCHAR, "movzbl",
384 USHORT, "movzwl",
4d89f1ac 385 0, ""
7c801adb
ML
386 };
387
388char
389*toreg(type)
390 TWORD type;
391{
392 struct type_move *p;
393
4d89f1ac 394 for ( p=toreg_strs; p->fromtype != 0; p++)
7c801adb
ML
395 if (p->fromtype == type) return(p->tostrng);
396
397 /* type not found, must be a pointer type */
398 return("movl");
399}
400/* tbl */
e2a25814 401#endif
7c801adb
ML
402
403
404main( argc, argv ) char *argv[]; {
405#ifdef BUFSTDERR
406 char errbuf[BUFSIZ];
407 setbuf(stderr, errbuf);
408#endif
409 return(mainp1( argc, argv ));
410 }
411
412struct sw heapsw[SWITSZ]; /* heap for switches */
413
414genswitch(p,n) register struct sw *p;{
415 /* p points to an array of structures, each consisting
416 of a constant value and a label.
417 The first is >=0 if there is a default label;
418 its value is the label number
419 The entries p[1] to p[n] are the nontrivial cases
420 */
421 register i;
422 register CONSZ j, range;
423 register dlab, swlab;
424
41733f0f 425 if( nerrors ) return;
7c801adb
ML
426 range = p[n].sval-p[1].sval;
427
428 if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
429
430 swlab = getlab();
431 dlab = p->slab >= 0 ? p->slab : getlab();
432
433 /* already in r0 */
434 printf(" casel r0,$%ld,$%ld\n", p[1].sval, range);
435 printf("L%d:\n", swlab);
436 for( i=1,j=p[1].sval; i<=n; j++) {
437 printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
438 swlab);
439 }
440
441 if( p->slab >= 0 ) branch( dlab );
442 else printf("L%d:\n", dlab);
443 return;
444
445 }
446
447 if( n>8 ) { /* heap switch */
448
449 heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
450 makeheap(p, n, 1); /* build heap */
451
452 walkheap(1, n); /* produce code */
453
454 if( p->slab >= 0 )
455 branch( dlab );
456 else
457 printf("L%d:\n", dlab);
458 return;
459 }
460
461 /* debugging code */
462
463 /* out for the moment
464 if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
465 */
466
467 /* simple switch code */
468
469 for( i=1; i<=n; ++i ){
470 /* already in r0 */
471
88bb0c9f 472 putstr( " cmpl r0,$" );
7c801adb
ML
473 printf( CONFMT, p[i].sval );
474 printf( "\n jeql L%d\n", p[i].slab );
475 }
476
477 if( p->slab>=0 ) branch( p->slab );
478 }
479
480makeheap(p, m, n)
481register struct sw *p;
482{
483 register int q;
484
72daa130 485 q = selectheap(m);
7c801adb
ML
486 heapsw[n] = p[q];
487 if( q>1 ) makeheap(p, q-1, 2*n);
488 if( q<m ) makeheap(p+q, m-q, 2*n+1);
489}
490
72daa130 491selectheap(m) {
7c801adb
ML
492 register int l,i,k;
493
494 for(i=1; ; i*=2)
495 if( (i-1) > m ) break;
496 l = ((k = i/2 - 1) + 1)/2;
497 return( l + (m-k < l ? m-k : l));
498}
499
500walkheap(start, limit)
501{
502 int label;
503
504
505 if( start > limit ) return;
506 printf(" cmpl r0,$%d\n", heapsw[start].sval);
507 printf(" jeql L%d\n", heapsw[start].slab);
508 if( (2*start) > limit ) {
509 printf(" jbr L%d\n", heapsw[0].slab);
510 return;
511 }
512 if( (2*start+1) <= limit ) {
513 label = getlab();
514 printf(" jgtr L%d\n", label);
515 } else
516 printf(" jgtr L%d\n", heapsw[0].slab);
517 walkheap( 2*start, limit);
518 if( (2*start+1) <= limit ) {
519 printf("L%d:\n", label);
520 walkheap( 2*start+1, limit);
521 }
522}