utah rcsid 1.6 87/04/16 23:32:35: Replaced hardops() with VAX PCC version
[unix-history] / usr / src / old / pcc / ccom.tahoe / local2.c
CommitLineData
f2b49199 1#ifndef lint
20018a56 2static char sccsid[] = "@(#)local2.c 1.15 (Berkeley) %G%";
f2b49199
SL
3#endif
4
ebdd0416
SL
5# include "pass2.h"
6# include <ctype.h>
895241c8
SL
7
8# define putstr(s) fputs((s), stdout)
73fe5b3f 9# define ISCHAR(p) (p->in.type == UCHAR || p->in.type == CHAR)
895241c8 10
f2b49199
SL
11# ifdef FORT
12int ftlab1, ftlab2;
13# endif
14/* a lot of the machine dependent parts of the second pass */
15
16# define BITMASK(n) ((1L<<n)-1)
17
18# ifndef ONEPASS
19where(c){
20 fprintf( stderr, "%s, line %d: ", filename, lineno );
21 }
22# endif
23
24lineid( l, fn ) char *fn; {
25 /* identify line l and file fn */
26 printf( "# line %d, file %s\n", l, fn );
27 }
28
29int ent_mask;
30
31eobl2(){
32 register OFFSZ spoff; /* offset from stack pointer */
33#ifndef FORT
34 extern int ftlab1, ftlab2;
35#endif
36
37 spoff = maxoff;
38 spoff /= SZCHAR;
39 SETOFF(spoff,4);
40#ifdef FORT
41#ifndef FLEXNAMES
42 printf( " .set .F%d,%d\n", ftnno, spoff );
43#else
44 /* SHOULD BE L%d ... ftnno but must change pc/f77 */
45 printf( " .set LF%d,%d\n", ftnno, spoff );
46#endif
47 printf( " .set LWM%d,0x%x\n", ftnno, ent_mask&0x1ffc|0x1000);
48#else
49 printf( " .set L%d,0x%x\n", ftnno, ent_mask&0x1ffc);
50 printf( "L%d:\n", ftlab1);
51 if( maxoff > AUTOINIT )
52 printf( " subl3 $%d,fp,sp\n", spoff);
53 printf( " jbr L%d\n", ftlab2);
54#endif
55 ent_mask = 0;
56 maxargs = -1;
57 }
58
59struct hoptab { int opmask; char * opstring; } ioptab[] = {
60
61 PLUS, "add",
62 MINUS, "sub",
63 MUL, "mul",
64 DIV, "div",
65 MOD, "div",
66 OR, "or",
67 ER, "xor",
68 AND, "and",
69 -1, "" };
70
71hopcode( f, o ){
72 /* output the appropriate string from the above table */
73
74 register struct hoptab *q;
75
76 if(asgop(o))
77 o = NOASG o;
78 for( q = ioptab; q->opmask>=0; ++q ){
79 if( q->opmask == o ){
80 if(f == 'E')
81 printf( "e%s", q->opstring);
82 else
83 printf( "%s%c", q->opstring, tolower(f));
84 return;
85 }
86 }
87 cerror( "no hoptab for %s", opst[o] );
88 }
89
90char *
91rnames[] = { /* keyed to register number tokens */
92
93 "r0", "r1",
94 "r2", "r3", "r4", "r5",
95 "r6", "r7", "r8", "r9", "r10", "r11",
96 "r12", "fp", "sp", "pc",
97 };
98
99/* output register name and update entry mask */
100char *
101rname(r)
102 register int r;
103{
104
105 ent_mask |= 1<<r;
106 return(rnames[r]);
107}
108
109int rstatus[] = {
110 SAREG|STAREG, SAREG|STAREG,
111 SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG,
112 SAREG, SAREG, SAREG, SAREG, SAREG, SAREG,
113 SAREG, SAREG, SAREG, SAREG,
114 };
115
116tlen(p) NODE *p;
117{
118 switch(p->in.type) {
119 case CHAR:
120 case UCHAR:
121 return(1);
122
123 case SHORT:
124 case USHORT:
125 return(2);
126
127 case DOUBLE:
128 return(8);
129
130 default:
131 return(4);
132 }
133}
134
f1824a4b
SL
135anyfloat(p, q)
136 NODE *p, *q;
137{
138 register TWORD tp, tq;
139
140 tp = p->in.type;
141 tq = q->in.type;
142 return (tp == FLOAT || tp == DOUBLE || tq == FLOAT || tq == DOUBLE);
143}
144
f2b49199
SL
145prtype(n) NODE *n;
146{
147 switch (n->in.type)
148 {
149
150 case DOUBLE:
895241c8 151 putchar('d');
f2b49199
SL
152 return;
153
154 case FLOAT:
895241c8 155 putchar('f');
f2b49199
SL
156 return;
157
158 case INT:
159 case UNSIGNED:
895241c8 160 putchar('l');
f2b49199
SL
161 return;
162
163 case SHORT:
164 case USHORT:
895241c8 165 putchar('w');
f2b49199
SL
166 return;
167
168 case CHAR:
169 case UCHAR:
895241c8 170 putchar('b');
f2b49199
SL
171 return;
172
173 default:
174 if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
175 else {
895241c8 176 putchar('l');
f2b49199
SL
177 return;
178 }
179 }
180}
181
182zzzcode( p, c ) register NODE *p; {
183 register int m;
184 int val;
185 switch( c ){
186
187 case 'N': /* logical ops, turned into 0-1 */
188 /* use register given by register 1 */
189 cbgen( 0, m=getlab(), 'I' );
190 deflab( p->bn.label );
191 printf( " clrl %s\n", rname(getlr( p, '1' )->tn.rval) );
192 deflab( m );
193 return;
194
195 case 'P':
196 cbgen( p->in.op, p->bn.label, c );
197 return;
198
8acf7c89 199 case 'G': /* i *= f; asgops with int lhs and float rhs */
f2b49199 200 {
8acf7c89
DS
201 register NODE *l, *r, *s;
202 int lt, rt;
f2b49199 203
8acf7c89
DS
204 l = p->in.left;
205 r = p->in.right;
206 s = talloc();
207 rt = r->in.type;
208 lt = l->in.type;
209
210 if (lt != INT && lt != UNSIGNED) {
211 s->in.op = SCONV;
212 s->in.left = l;
213 s->in.type = ISUNSIGNED(lt) ? UNSIGNED : INT;
214 zzzcode(s, 'U');
215 putstr("\n\t");
216 }
f2b49199 217
8acf7c89
DS
218 if (ISUNSIGNED(lt)) {
219 s->in.op = SCONV;
220 s->in.left = lt == UNSIGNED ? l : resc;
221 s->in.type = rt;
222 unsigned_to_float(s);
223 } else {
224 putstr("cvl");
225 prtype(r);
226 putchar('\t');
227 adrput(lt == INT ? l : resc);
f2b49199 228 }
8acf7c89
DS
229 putstr("\n\t");
230
231 hopcode(rt == FLOAT ? 'F' : 'D', p->in.op);
895241c8 232 putchar('\t');
f2b49199 233 adrput(r);
8acf7c89
DS
234
235 if (ISUNSIGNED(lt)) {
236 putstr("\n\t");
237 s->in.op = SCONV;
238 s->in.left = r; /* we need only the type */
239 s->in.type = UNSIGNED;
240 float_to_unsigned(s);
241 } else {
242 putstr("\n\tcv");
243 prtype(r);
244 putstr("l\t");
245 if (lt == INT)
246 adrput(l);
247 else
248 adrput(resc);
249 }
250 if (lt != INT) {
251 putstr("\n\t");
252 s->in.op = ASSIGN;
253 s->in.left = l;
254 s->in.right = resc;
255 s->in.type = lt;
256 zzzcode(s, 'U');
257 }
258
259 s->in.op = FREE;
f2b49199
SL
260 return;
261 }
262
263 case 'B': /* get oreg value in temp register for shift */
264 {
265 register NODE *r;
266 if (xdebug) eprint(p, 0, &val, &val);
267 r = p->in.right;
268 if( tlen(r) == sizeof(int) && r->in.type != FLOAT )
895241c8 269 putstr("movl");
f2b49199 270 else {
895241c8 271 putstr(ISUNSIGNED(r->in.type) ? "movz" : "cvt");
f2b49199 272 prtype(r);
895241c8 273 putchar('l');
f2b49199
SL
274 }
275 return;
276 }
277
278 case 'C': /* num bytes pushed on arg stack */
279 {
280 extern int gc_numbytes;
281 extern int xdebug;
282
283 if (xdebug) printf("->%d<-",gc_numbytes);
284
285 printf("call%c $%d",
286 (p->in.left->in.op==ICON && gc_numbytes<60)?'f':'s',
287 gc_numbytes+4);
288 /* dont change to double (here's the only place to catch it) */
289 if(p->in.type == FLOAT)
290 rtyflg = 1;
291 return;
292 }
293
294 case 'D': /* INCR and DECR */
8acf7c89 295 zzzcode(p->in.left, 'U');
895241c8 296 putstr("\n ");
f2b49199
SL
297
298 case 'E': /* INCR and DECR, FOREFF */
299 if (p->in.right->tn.lval == 1)
300 {
895241c8 301 putstr(p->in.op == INCR ? "inc" : "dec");
f2b49199 302 prtype(p->in.left);
895241c8 303 putchar('\t');
f2b49199
SL
304 adrput(p->in.left);
305 return;
306 }
895241c8 307 putstr(p->in.op == INCR ? "add" : "sub");
f2b49199 308 prtype(p->in.left);
895241c8 309 putstr("2 ");
f2b49199 310 adrput(p->in.right);
895241c8 311 putchar(',');
f2b49199
SL
312 adrput(p->in.left);
313 return;
314
315 case 'F': /* masked constant for fields */
7412b41b 316 printf(ACONFMT, (p->in.right->tn.lval&((1<<fldsz)-1))<<fldshf);
f2b49199
SL
317 return;
318
319 case 'H': /* opcode for shift */
320 if(p->in.op == LS || p->in.op == ASG LS)
895241c8 321 putstr("shll");
f2b49199 322 else if(ISUNSIGNED(p->in.left->in.type))
895241c8 323 putstr("shrl");
f2b49199 324 else
895241c8 325 putstr("shar");
f2b49199
SL
326 return;
327
328 case 'L': /* type of left operand */
329 case 'R': /* type of right operand */
330 {
331 register NODE *n;
332 extern int xdebug;
333
334 n = getlr ( p, c);
335 if (xdebug) printf("->%d<-", n->in.type);
336
337 prtype(n);
338 return;
339 }
340
f1824a4b 341 case 'M': { /* initiate ediv for mod and unsigned div */
f2b49199
SL
342 register char *r;
343 m = getlr(p, '1')->tn.rval;
344 r = rname(m);
345 printf("\tclrl\t%s\n\tmovl\t", r);
346 adrput(p->in.left);
347 printf(",%s\n", rname(m+1));
348 if(!ISUNSIGNED(p->in.type)) { /* should be MOD */
349 m = getlab();
350 printf("\tjgeq\tL%d\n\tmnegl\t$1,%s\n", m, r);
351 deflab(m);
352 }
f2b49199 353 return;
f1824a4b 354 }
f2b49199 355
f1824a4b
SL
356 case 'T': { /* rounded structure length for arguments */
357 int size = p->stn.stsize;
f2b49199
SL
358 SETOFF( size, 4);
359 printf("movab -%d(sp),sp", size);
360 return;
f1824a4b 361 }
f2b49199
SL
362
363 case 'S': /* structure assignment */
1d43595d
SL
364 stasg(p);
365 break;
f2b49199 366
73fe5b3f
SL
367 case 'X': /* multiplication for short and char */
368 if (ISUNSIGNED(p->in.left->in.type))
369 printf("\tmovz");
370 else
371 printf("\tcvt");
372 zzzcode(p, 'L');
373 printf("l\t");
374 adrput(p->in.left);
375 printf(",");
376 adrput(&resc[0]);
377 printf("\n");
378 if (ISUNSIGNED(p->in.right->in.type))
379 printf("\tmovz");
380 else
381 printf("\tcvt");
382 zzzcode(p, 'R');
383 printf("l\t");
384 adrput(p->in.right);
385 printf(",");
386 adrput(&resc[1]);
387 printf("\n");
388 return;
389
f1824a4b
SL
390 case 'U': /* SCONV */
391 case 'V': /* SCONV with FORCC */
392 sconv(p, c == 'V');
393 break;
394
8acf7c89
DS
395 case 'W': /* SCONV float/double => unsigned */
396 putstr("ld");
397 prtype(p->in.left);
398 putchar('\t');
399 adrput(p->in.left);
400 putstr("\n\t");
401 float_to_unsigned(p);
402 break;
403
404 case 'Y': /* SCONV unsigned => float/double */
405 unsigned_to_float(p); /* stores into accumulator */
406 putstr("\n\tst");
407 prtype(p);
408 putchar('\t');
409 adrput(resc);
410 break;
411
f1824a4b
SL
412 case 'Z':
413 p = p->in.right;
414 switch (p->in.type) {
415 case SHORT: {
416 short w = p->tn.lval;
417 p->tn.lval = w;
418 break;
419 }
420 case CHAR: {
421 char c = p->tn.lval;
422 p->tn.lval = c;
423 break;
424 }
425 }
426 printf("$%d", p->tn.lval);
427 break;
428
1d43595d
SL
429 default:
430 cerror( "illegal zzzcode" );
1d43595d 431 }
f1824a4b 432}
f2b49199 433
1d43595d 434#define MOVB(dst, src, off) { \
895241c8 435 putstr("\tmovb\t"); upput(src, off); putchar(','); \
1d43595d
SL
436 upput(dst, off); putchar('\n'); \
437}
438#define MOVW(dst, src, off) { \
895241c8 439 putstr("\tmovw\t"); upput(src, off); putchar(','); \
1d43595d
SL
440 upput(dst, off); putchar('\n'); \
441}
442#define MOVL(dst, src, off) { \
895241c8 443 putstr("\tmovl\t"); upput(src, off); putchar(','); \
1d43595d
SL
444 upput(dst, off); putchar('\n'); \
445}
446/*
447 * Generate code for a structure assignment.
448 */
449stasg(p)
450 register NODE *p;
451{
452 register NODE *l, *r;
453 register int size;
454
455 switch (p->in.op) {
456 case STASG: /* regular assignment */
457 l = p->in.left;
458 r = p->in.right;
459 break;
460 case STARG: /* place arg on the stack */
461 l = getlr(p, '3');
462 r = p->in.left;
463 break;
464 default:
465 cerror("STASG bad");
466 /*NOTREACHED*/
467 }
468 /*
469 * Pun source for use in code generation.
470 */
471 switch (r->in.op) {
472 case ICON:
473 r->in.op = NAME;
474 break;
475 case REG:
476 r->in.op = OREG;
477 break;
478 default:
479 cerror( "STASG-r" );
480 /*NOTREACHED*/
481 }
482 size = p->stn.stsize;
483 if (size <= 0 || size > 65535)
484 cerror("structure size out of range");
485 /*
486 * Generate optimized code based on structure size
487 * and alignment properties....
488 */
489 switch (size) {
490
491 case 1:
895241c8 492 putstr("\tmovb\t");
1d43595d
SL
493 optimized:
494 adrput(r);
895241c8 495 putchar(',');
1d43595d 496 adrput(l);
895241c8 497 putchar('\n');
1d43595d
SL
498 break;
499
500 case 2:
501 if (p->stn.stalign != 2) {
502 MOVB(l, r, SZCHAR);
895241c8 503 putstr("\tmovb\t");
1d43595d 504 } else
895241c8 505 putstr("\tmovw\t");
1d43595d
SL
506 goto optimized;
507
508 case 4:
509 if (p->stn.stalign != 4) {
510 if (p->stn.stalign != 2) {
511 MOVB(l, r, 3*SZCHAR);
512 MOVB(l, r, 2*SZCHAR);
513 MOVB(l, r, 1*SZCHAR);
895241c8 514 putstr("\tmovb\t");
1d43595d
SL
515 } else {
516 MOVW(l, r, SZSHORT);
895241c8 517 putstr("\tmovw\t");
f2b49199 518 }
1d43595d 519 } else
895241c8 520 putstr("\tmovl\t");
1d43595d
SL
521 goto optimized;
522
523 case 6:
524 if (p->stn.stalign != 2)
525 goto movblk;
526 MOVW(l, r, 2*SZSHORT);
527 MOVW(l, r, 1*SZSHORT);
895241c8 528 putstr("\tmovw\t");
1d43595d
SL
529 goto optimized;
530
531 case 8:
532 if (p->stn.stalign == 4) {
533 MOVL(l, r, SZLONG);
895241c8 534 putstr("\tmovl\t");
1d43595d
SL
535 goto optimized;
536 }
537 /* fall thru...*/
f2b49199 538
1d43595d
SL
539 default:
540 movblk:
541 /*
542 * Can we ever get a register conflict with R1 here?
543 */
895241c8 544 putstr("\tmovab\t");
1d43595d 545 adrput(l);
895241c8 546 putstr(",r1\n\tmovab\t");
1d43595d
SL
547 adrput(r);
548 printf(",r0\n\tmovl\t$%d,r2\n\tmovblk\n", size);
549 rname(R2);
f2b49199 550 break;
1d43595d
SL
551 }
552 /*
553 * Reverse above pun for reclaim.
554 */
555 if (r->in.op == NAME)
556 r->in.op = ICON;
557 else if (r->in.op == OREG)
558 r->in.op = REG;
559}
f2b49199 560
1d43595d
SL
561/*
562 * Output the address of the second item in the
563 * pair pointed to by p.
564 */
565upput(p, size)
566 register NODE *p;
567{
568 CONSZ save;
569
570 if (p->in.op == FLD)
571 p = p->in.left;
572 switch (p->in.op) {
573
574 case NAME:
575 case OREG:
576 save = p->tn.lval;
577 p->tn.lval += size/SZCHAR;
578 adrput(p);
579 p->tn.lval = save;
580 break;
581
582 case REG:
583 if (size == SZLONG) {
895241c8 584 putstr(rname(p->tn.rval+1));
1d43595d 585 break;
f2b49199 586 }
1d43595d
SL
587 /* fall thru... */
588
589 default:
590 cerror("illegal upper address op %s size %d",
591 opst[p->tn.op], size);
592 /*NOTREACHED*/
f2b49199 593 }
1d43595d 594}
f2b49199 595
8acf7c89
DS
596/*
597 * Convert a float or double in the accumulator into an unsigned int.
598 * Unlike the vax, the tahoe stores 0 into the destination
599 * on a conversion of > 2 ** 31, so we compensate.
600 */
601float_to_unsigned(p)
602 NODE *p;
603{
604 register NODE *l = p->in.left;
605 int label1 = getlab();
606 int label2 = getlab();
607 int label3 = getlab();
608
609 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50000000", label1);
610 if (l->in.type == DOUBLE)
611 putstr(", 0x00000000");
612 putstr(" # .double 2147483648\n\t.text\n\tcmp");
613 prtype(l);
614 printf("\tL%d\n\tjlss\tL%d\n\tsub", label1, label2);
615 prtype(l);
616 printf("\tL%d\n\tcv", label1);
617 prtype(l);
618 putstr("l\t");
619 adrput(resc);
620 putstr("\n\taddl2\t$-2147483648,");
621 adrput(resc);
622 printf("\n\tjbr\tL%d\nL%d:\n\tcv", label3, label2);
623 prtype(l);
624 putstr("l\t");
625 adrput(resc);
626 printf("\nL%d:", label3);
627}
628
629/*
630 * Convert an unsigned int into a float or double, leaving the result
631 * in the accumulator.
632 */
633unsigned_to_float(p)
634 register NODE *p;
635{
636 int label1 = getlab();
637 int label2 = getlab();
638
639 printf(".data\n\t.align\t2\nL%d:\n\t.long\t0x50800000", label2);
640 if (p->in.type == DOUBLE)
641 putstr(", 0x00000000");
642 putstr(" # .double 4294967296\n\t.text\n\tmovl\t");
643 adrput(p->in.left);
644 putchar(',');
645 adrput(resc);
646 putstr("\n\tcvl");
647 prtype(p);
648 putchar('\t');
649 adrput(resc);
650 printf("\n\tjgeq\tL%d\n\taddd\tL%d\nL%d:", label1, label2, label1);
651}
652
26ab1ae0
DS
653/*
654 * Prlen() is a cheap prtype()...
655 */
656static char convtab[SZINT/SZCHAR + 1] = {
657 '?', 'b', 'w', '?', 'l'
658};
659#define prlen(len) putchar(convtab[len])
660
661
52b983f1
DS
662/*
663 * Generate code for integral scalar conversions.
26ab1ae0
DS
664 * Some of this code is designed to work around a tahoe misfeature
665 * that causes sign- and zero- extension to be defeated in
666 * certain circumstances.
667 * Basically if the source operand of a CVT or MOVZ instruction is
668 * shorter than the destination, and the source is a register
669 * or an immediate constant, sign- and zero- extension are
670 * ignored and the high bits of the source are copied. (Note
671 * that zero-extension is not a problem for immediate
672 * constants.)
52b983f1
DS
673 */
674sconv(p, forcc)
675 NODE *p;
676 int forcc;
677{
678 register NODE *src, *dst;
679 register NODE *tmp;
680 register int srclen, dstlen;
681 int srctype, dsttype;
682 int val;
683
684 if (p->in.op == ASSIGN) {
685 src = getlr(p, 'R');
686 dst = getlr(p, 'L');
687 dstlen = tlen(dst);
688 dsttype = dst->in.type;
689 } else /* if (p->in.op == SCONV || optype(p->in.op) == LTYPE) */ {
690 src = getlr(p, 'L');
691 dst = getlr(p, '1');
692 dstlen = tlen(p);
693 dsttype = p->in.type;
694 }
695
26ab1ae0
DS
696 if (src->in.op == REG) {
697 srclen = SZINT/SZCHAR;
698 srctype = ISUNSIGNED(src->in.type) ? UNSIGNED : INT;
699 } else {
700 srclen = tlen(src);
701 srctype = src->in.type;
702 }
703
704 if (src->in.op == ICON) {
705 if (src->tn.lval == 0) {
706 putstr("clr");
707 prtype(dst);
708 putchar('\t');
709 adrput(dst);
710 return;
711 }
712 if (dstlen < srclen) {
713 switch (dsttype) {
714 case CHAR:
715 src->tn.lval = (char) src->tn.lval;
716 break;
717 case UCHAR:
718 src->tn.lval = (unsigned char) src->tn.lval;
719 break;
720 case SHORT:
721 src->tn.lval = (short) src->tn.lval;
722 break;
723 case USHORT:
724 src->tn.lval = (unsigned short) src->tn.lval;
725 break;
726 }
727 }
728 if (dst->in.op == REG) {
729 dsttype = INT;
730 dstlen = SZINT/SZCHAR;
731 }
732 srctype = dsttype;
733 srclen = dstlen;
734 }
52b983f1
DS
735
736 if (srclen < dstlen) {
737 if (srctype == CHAR && dsttype == USHORT && dst->in.op == REG) {
738 /* (unsigned short) c; => sign extend to 16 bits */
c3446016 739 putstr("cvtbl\t");
52b983f1
DS
740 adrput(src);
741 putstr(",-(sp)\n\tmovzwl\t2(sp),");
742 adrput(dst);
743 putstr("\n\tmovab\t4(sp),sp");
744 if (forcc) {
745 /* inverted test */
746 putstr("\n\tcmpl\t$0,");
747 adrput(dst);
748 }
749 return;
750 }
751 genconv(ISUNSIGNED(srctype),
752 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
753 src, dst);
754 return;
755 }
756
757 if (srclen > dstlen && dst->in.op == REG) {
26ab1ae0 758 /* if dst is a register, the result must look like an int */
52b983f1
DS
759 if (src->in.op == REG) {
760 if (ISUNSIGNED(dsttype)) {
761 val = (1 << dstlen * SZCHAR) - 1;
762 if (src->tn.rval == dst->tn.rval)
763 /* conversion in place */
c3446016 764 printf("andl2\t$%#x,", val);
52b983f1 765 else {
c3446016 766 printf("andl3\t$%#x,", val);
52b983f1
DS
767 adrput(src);
768 putchar(',');
769 }
770 adrput(dst);
771 return;
772 }
26ab1ae0
DS
773 /*
774 * Sign extension in register can also be
775 * accomplished by shifts, but unfortunately
776 * shifts are extremely slow, due to the lack
777 * of a barrel shifter.
778 */
779 putstr("pushl\t");
52b983f1 780 adrput(src);
26ab1ae0
DS
781 putstr("\n\tcvt");
782 prlen(dstlen);
783 printf("l\t%d(sp),", SZINT/SZCHAR - dstlen);
52b983f1 784 adrput(dst);
26ab1ae0
DS
785 putstr("\n\tmovab\t4(sp),sp");
786 if (forcc) {
787 /* inverted test */
788 putstr("\n\tcmpl\t$0,");
789 adrput(dst);
790 }
52b983f1
DS
791 return;
792 }
793 tmp = talloc();
794 if ((src->in.op == UNARY MUL &&
795 ((src->in.left->in.op == NAME ||
796 (src->in.left->in.op == ICON)))) ||
797 (src->in.op == OREG && !R2TEST(src->tn.rval))) {
798 /* we can increment src's address & pun it */
799 *tmp = *src;
800 tmp->tn.lval += srclen - dstlen;
801 } else {
802 /* we must store src's address */
803 *tmp = *dst;
26ab1ae0
DS
804 putstr("mova");
805 prlen(srclen);
806 putchar('\t');
52b983f1
DS
807 adrput(src);
808 putchar(',');
809 adrput(tmp);
c3446016 810 putstr("\n\t");
52b983f1
DS
811 tmp->tn.op = OREG;
812 tmp->tn.lval = srclen - dstlen;
813 }
814 genconv(ISUNSIGNED(dsttype), dstlen, SZINT/SZCHAR, tmp, dst);
815 tmp->in.op = FREE;
816 return;
817 }
818
819 genconv(ISUNSIGNED(dsttype),
820 srclen, dst->in.op == REG ? SZINT/SZCHAR : dstlen,
821 src, dst);
822}
823
824genconv(usrc, srclen, dstlen, src, dst)
26ab1ae0
DS
825 int usrc;
826 register int srclen, dstlen;
52b983f1
DS
827 NODE *src, *dst;
828{
52b983f1
DS
829 if (srclen != dstlen) {
830 if (usrc && srclen < dstlen)
c3446016 831 putstr("movz");
52b983f1 832 else
c3446016 833 putstr("cvt");
26ab1ae0 834 prlen(srclen);
52b983f1 835 } else
c3446016 836 putstr("mov");
26ab1ae0 837 prlen(dstlen);
52b983f1
DS
838 putchar('\t');
839 adrput(src);
840 putchar(',');
841 adrput(dst);
842}
f1824a4b 843
f2b49199
SL
844rmove( rt, rs, t ) TWORD t;{
845 printf( " movl %s,%s\n", rname(rs), rname(rt) );
846 if(t==DOUBLE)
847 printf( " movl %s,%s\n", rname(rs+1), rname(rt+1) );
848 }
849
850struct respref
851respref[] = {
852 INTAREG|INTBREG, INTAREG|INTBREG,
853 INAREG|INBREG, INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
854 INTEMP, INTEMP,
855 FORARG, FORARG,
856 INTEMP, INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
857 0, 0 };
858
859setregs(){ /* set up temporary registers */
860 fregs = 6; /* tbl- 6 free regs on Tahoe (0-5) */
861 }
862
ebdd0416 863#ifndef szty
f2b49199
SL
864szty(t) TWORD t;{ /* size, in registers, needed to hold thing of type t */
865 return(t==DOUBLE ? 2 : 1 );
866 }
ebdd0416 867#endif
f2b49199
SL
868
869rewfld( p ) NODE *p; {
870 return(1);
871 }
872
873callreg(p) NODE *p; {
874 return( R0 );
875 }
876
877base( p ) register NODE *p; {
878 register int o = p->in.op;
879
880 if( (o==ICON && p->in.name[0] != '\0')) return( 100 ); /* ie no base reg */
881 if( o==REG ) return( p->tn.rval );
882 if( (o==PLUS || o==MINUS) && p->in.left->in.op == REG && p->in.right->in.op==ICON)
883 return( p->in.left->tn.rval );
884 if( o==OREG && !R2TEST(p->tn.rval) && (p->in.type==INT || p->in.type==UNSIGNED || ISPTR(p->in.type)) )
885 return( p->tn.rval + 0200*1 );
886 return( -1 );
887 }
888
889offset( p, tyl ) register NODE *p; int tyl; {
890
891 if(tyl > 8) return( -1 );
892 if( tyl==1 && p->in.op==REG && (p->in.type==INT || p->in.type==UNSIGNED) ) return( p->tn.rval );
893 if( (p->in.op==LS && p->in.left->in.op==REG && (p->in.left->in.type==INT || p->in.left->in.type==UNSIGNED) &&
894 (p->in.right->in.op==ICON && p->in.right->in.name[0]=='\0')
895 && (1<<p->in.right->tn.lval)==tyl))
896 return( p->in.left->tn.rval );
897 return( -1 );
898 }
899
900makeor2( p, q, b, o) register NODE *p, *q; register int b, o; {
901 register NODE *t;
902 register int i;
903 NODE *f;
904
905 p->in.op = OREG;
906 f = p->in.left; /* have to free this subtree later */
907
908 /* init base */
909 switch (q->in.op) {
910 case ICON:
911 case REG:
912 case OREG:
913 t = q;
914 break;
915
916 case MINUS:
917 q->in.right->tn.lval = -q->in.right->tn.lval;
918 case PLUS:
919 t = q->in.right;
920 break;
921
922 case UNARY MUL:
923 t = q->in.left->in.left;
924 break;
925
926 default:
927 cerror("illegal makeor2");
928 }
929
930 p->tn.lval = t->tn.lval;
931#ifndef FLEXNAMES
932 for(i=0; i<NCHNAM; ++i)
933 p->in.name[i] = t->in.name[i];
934#else
935 p->in.name = t->in.name;
936#endif
937
938 /* init offset */
939 p->tn.rval = R2PACK( (b & 0177), o, (b>>7) );
940
941 tfree(f);
942 return;
943 }
944
945canaddr( p ) NODE *p; {
946 register int o = p->in.op;
947
948 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
949 return(0);
950 }
951
ebdd0416 952#ifndef shltype
f2b49199
SL
953shltype( o, p ) register NODE *p; {
954 return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UNARY MUL && shumul(p->in.left)) );
955 }
ebdd0416 956#endif
f2b49199
SL
957
958flshape( p ) NODE *p; {
959 register int o = p->in.op;
960
961 if( o==NAME || o==REG || o==ICON || o==OREG || (o==UNARY MUL && shumul(p->in.left)) ) return(1);
962 return(0);
963 }
964
965shtemp( p ) register NODE *p; {
966 if( p->in.op == STARG ) p = p->in.left;
967 return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG || (p->in.op==UNARY MUL && shumul(p->in.left)) );
968 }
969
970shumul( p ) register NODE *p; {
971 register int o;
972 extern int xdebug;
973
974 if (xdebug) {
975 printf("\nshumul:op=%d,lop=%d,rop=%d", p->in.op, p->in.left->in.op, p->in.right->in.op);
976 printf(" prname=%s,plty=%d, prlval=%D\n", p->in.right->in.name, p->in.left->in.type, p->in.right->tn.lval);
977 }
978
979 o = p->in.op;
980 if(( o == NAME || (o == OREG && !R2TEST(p->tn.rval)) || o == ICON )
981 && p->in.type != PTR+DOUBLE)
982 return( STARNM );
983
984 return( 0 );
985 }
986
987special( p, shape ) register NODE *p; {
988 if( shape==SIREG && p->in.op == OREG && R2TEST(p->tn.rval) ) return(1);
989 else return(0);
990}
991
992adrcon( val ) CONSZ val; {
7412b41b 993 printf(ACONFMT, val);
f2b49199
SL
994 }
995
996conput( p ) register NODE *p; {
997 switch( p->in.op ){
998
999 case ICON:
1000 acon( p );
1001 return;
1002
1003 case REG:
895241c8 1004 putstr(rname(p->tn.rval));
f2b49199
SL
1005 return;
1006
1007 default:
1008 cerror( "illegal conput" );
1009 }
1010 }
1011
1012insput( p ) NODE *p; {
1013 cerror( "insput" );
1014 }
1015
f2b49199
SL
1016adrput( p ) register NODE *p; {
1017 register int r;
1018 /* output an address, with offsets, from p */
1019
1020 if( p->in.op == FLD ){
1021 p = p->in.left;
1022 }
1023 switch( p->in.op ){
1024
1025 case NAME:
1026 acon( p );
1027 return;
1028
1029 case ICON:
1030 /* addressable value of the constant */
895241c8 1031 putchar('$');
f2b49199
SL
1032 acon( p );
1033 return;
1034
1035 case REG:
895241c8 1036 putstr(rname(p->tn.rval));
f2b49199
SL
1037 if(p->in.type == DOUBLE) /* for entry mask */
1038 (void) rname(p->tn.rval+1);
1039 return;
1040
1041 case OREG:
1042 r = p->tn.rval;
1043 if( R2TEST(r) ){ /* double indexing */
1044 register int flags;
1045
1046 flags = R2UPK3(r);
895241c8 1047 if( flags & 1 ) putchar('*');
f2b49199
SL
1048 if( p->tn.lval != 0 || p->in.name[0] != '\0' ) acon(p);
1049 if( R2UPK1(r) != 100) printf( "(%s)", rname(R2UPK1(r)) );
1050 printf( "[%s]", rname(R2UPK2(r)) );
1051 return;
1052 }
1053 if( r == FP && p->tn.lval > 0 ){ /* in the argument region */
1054 if( p->in.name[0] != '\0' ) werror( "bad arg temp" );
1055 printf( CONFMT, p->tn.lval );
895241c8 1056 putstr( "(fp)" );
f2b49199
SL
1057 return;
1058 }
1059 if( p->tn.lval != 0 || p->in.name[0] != '\0') acon( p );
1060 printf( "(%s)", rname(p->tn.rval) );
1061 return;
1062
1063 case UNARY MUL:
1064 /* STARNM or STARREG found */
1065 if( tshape(p, STARNM) ) {
895241c8 1066 putchar( '*' );
f2b49199
SL
1067 adrput( p->in.left);
1068 }
1069 return;
1070
1071 default:
1072 cerror( "illegal address" );
1073 return;
1074
1075 }
1076
1077 }
1078
1079acon( p ) register NODE *p; { /* print out a constant */
1080
1081 if( p->in.name[0] == '\0' ){
1082 printf( CONFMT, p->tn.lval);
895241c8
SL
1083 return;
1084 } else {
f2b49199
SL
1085#ifndef FLEXNAMES
1086 printf( "%.8s", p->in.name );
1087#else
895241c8 1088 putstr(p->in.name);
f2b49199 1089#endif
895241c8
SL
1090 if (p->tn.lval != 0) {
1091 putchar('+');
1092 printf(CONFMT, p->tn.lval);
f2b49199 1093 }
895241c8 1094 }
f2b49199
SL
1095 }
1096
1097genscall( p, cookie ) register NODE *p; {
1098 /* structure valued call */
1099 return( gencall( p, cookie ) );
1100 }
1101
1102genfcall( p, cookie ) register NODE *p; {
1103 register NODE *p1;
1104 register int m;
1105 static char *funcops[6] = {
1106 "sin", "cos", "sqrt", "exp", "log", "atan"
1107 };
1108
1109 /* generate function opcodes */
1110 if(p->in.op==UNARY FORTCALL && p->in.type==FLOAT &&
1111 (p1 = p->in.left)->in.op==ICON &&
1112 p1->tn.lval==0 && p1->in.type==INCREF(FTN|FLOAT)) {
1113#ifdef FLEXNAMES
1114 p1->in.name++;
1115#else
1116 strcpy(p1->in.name, p1->in.name[1]);
1117#endif
1118 for(m=0; m<6; m++)
1119 if(!strcmp(p1->in.name, funcops[m]))
1120 break;
1121 if(m >= 6)
1122 uerror("no opcode for fortarn function %s", p1->in.name);
1123 } else
1124 uerror("illegal type of fortarn function");
1125 p1 = p->in.right;
1126 p->in.op = FORTCALL;
1127 if(!canaddr(p1))
1128 order( p1, INAREG|INBREG|SOREG|STARREG|STARNM );
1129 m = match( p, INTAREG|INTBREG );
1130 return(m != MDONE);
1131}
1132
1133/* tbl */
1134int gc_numbytes;
1135/* tbl */
1136
1137gencall( p, cookie ) register NODE *p; {
1138 /* generate the call given by p */
1139 register NODE *p1, *ptemp;
1140 register int temp, temp1;
1141 register int m;
1142
1143 if( p->in.right ) temp = argsize( p->in.right );
1144 else temp = 0;
1145
1146 if( p->in.op == STCALL || p->in.op == UNARY STCALL ){
1147 /* set aside room for structure return */
1148
1149 if( p->stn.stsize > temp ) temp1 = p->stn.stsize;
1150 else temp1 = temp;
1151 }
1152
1153 if( temp > maxargs ) maxargs = temp;
1154 SETOFF(temp1,4);
1155
1156 if( p->in.right ){ /* make temp node, put offset in, and generate args */
1157 ptemp = talloc();
1158 ptemp->in.op = OREG;
1159 ptemp->tn.lval = -1;
1160 ptemp->tn.rval = SP;
1161#ifndef FLEXNAMES
1162 ptemp->in.name[0] = '\0';
1163#else
1164 ptemp->in.name = "";
1165#endif
1166 ptemp->in.rall = NOPREF;
1167 ptemp->in.su = 0;
1168 genargs( p->in.right, ptemp );
1169 ptemp->in.op = FREE;
1170 }
1171
1172 p1 = p->in.left;
1173 if( p1->in.op != ICON ){
1174 if( p1->in.op != REG ){
1175 if( p1->in.op != OREG || R2TEST(p1->tn.rval) ){
1176 if( p1->in.op != NAME ){
1177 order( p1, INAREG );
1178 }
1179 }
1180 }
1181 }
1182
1183/* tbl
1184 setup gc_numbytes so reference to ZC works */
1185
1186 gc_numbytes = temp&(0x3ff);
1187
1188 p->in.op = UNARY CALL;
1189 m = match( p, INTAREG|INTBREG );
1190
1191 return(m != MDONE);
1192 }
1193
1194/* tbl */
1195char *
1196ccbranches[] = {
1197 "eql",
1198 "neq",
1199 "leq",
1200 "lss",
1201 "geq",
1202 "gtr",
1203 "lequ",
1204 "lssu",
1205 "gequ",
1206 "gtru",
1207 };
1208/* tbl */
1209
1210cbgen( o, lab, mode ) { /* printf conditional and unconditional branches */
1211
1212 if(o != 0 && (o < EQ || o > UGT ))
1213 cerror( "bad conditional branch: %s", opst[o] );
1214 printf( " j%s L%d\n",
1215 o == 0 ? "br" : ccbranches[o-EQ], lab );
1216 }
1217
1218nextcook( p, cookie ) NODE *p; {
1219 /* we have failed to match p with cookie; try another */
1220 if( cookie == FORREW ) return( 0 ); /* hopeless! */
1221 if( !(cookie&(INTAREG|INTBREG)) ) return( INTAREG|INTBREG );
1222 if( !(cookie&INTEMP) && asgop(p->in.op) ) return( INTEMP|INAREG|INTAREG|INTBREG|INBREG );
1223 return( FORREW );
1224 }
1225
1226lastchance( p, cook ) NODE *p; {
1227 /* forget it! */
1228 return(0);
1229 }
1230
1231optim2( p ) register NODE *p; {
1232# ifdef ONEPASS
1233 /* do local tree transformations and optimizations */
1234# define RV(p) p->in.right->tn.lval
ebdd0416 1235# define nncon(p) ((p)->in.op == ICON && (p)->in.name[0] == 0)
f1824a4b
SL
1236 register int o, i;
1237 register NODE *l, *r;
f2b49199 1238
f1824a4b
SL
1239 switch (o = p->in.op) {
1240
1241 case DIV: case ASG DIV:
1242 case MOD: case ASG MOD:
1243 /*
1244 * Change unsigned mods and divs to
1245 * logicals (mul is done in mip & c2)
1246 */
1247 if (ISUNSIGNED(p->in.left->in.type) && nncon(p->in.right) &&
1248 (i = ispow2(RV(p))) >= 0) {
1249 if (o == DIV || o == ASG DIV) {
1250 p->in.op = RS;
1251 RV(p) = i;
1252 } else {
1253 p->in.op = AND;
1254 RV(p)--;
1255 }
1256 if (asgop(o))
1257 p->in.op = ASG p->in.op;
1258 }
1259 return;
1260
1261 case SCONV:
1262 l = p->in.left;
1263 /* clobber conversions w/o side effects */
1264 if (!anyfloat(p, l) && l->in.op != PCONV &&
1265 tlen(p) == tlen(l)) {
1266 if (l->in.op != FLD)
1267 l->in.type = p->in.type;
1268 ncopy(p, l);
1269 l->in.op = FREE;
1270 }
1271 return;
1272
1273 case ASSIGN:
1274 /*
1275 * Try to zap storage conversions of non-float items.
1276 */
1277 r = p->in.right;
1278 if (r->in.op == SCONV && !anyfloat(r->in.left, r)) {
1279 int wdest, wconv, wsrc;
1280 wdest = tlen(p->in.left);
1281 wconv = tlen(r);
1282 /*
1283 * If size doesn't change across assignment or
1284 * conversion expands src before shrinking again
1285 * due to the assignment, delete conversion so
1286 * code generator can create optimal code.
1287 */
1288 if (wdest == wconv ||
1289 (wdest == (wsrc = tlen(r->in.left)) && wconv > wsrc)) {
1290 p->in.right = r->in.left;
1291 r->in.op = FREE;
1292 }
f2b49199 1293 }
f1824a4b 1294 return;
f2b49199
SL
1295 }
1296# endif
1297}
1298
1299struct functbl {
1300 int fop;
20018a56 1301 TWORD ftype;
f2b49199 1302 char *func;
20018a56
DS
1303 } opfunc[] = {
1304 DIV, TANY, "udiv",
1305 MOD, TANY, "urem",
1306 ASG DIV, TANY, "audiv",
1307 ASG MOD, TANY, "aurem",
1308 0, 0, 0 };
f2b49199
SL
1309
1310hardops(p) register NODE *p; {
1311 /* change hard to do operators into function calls. */
1312 register NODE *q;
1313 register struct functbl *f;
20018a56
DS
1314 register o;
1315 NODE *old,*temp;
f2b49199
SL
1316
1317 o = p->in.op;
20018a56
DS
1318 if( ! (optype(o)==BITYPE &&
1319 (ISUNSIGNED(p->in.left->in.type) ||
1320 ISUNSIGNED(p->in.right->in.type))) )
1321 return;
f2b49199
SL
1322
1323 for( f=opfunc; f->fop; f++ ) {
1324 if( o==f->fop ) goto convert;
20018a56 1325 }
f2b49199
SL
1326 return;
1327
1328 convert:
f2b49199 1329 if( asgop( o ) ) {
20018a56
DS
1330 old = NIL;
1331 switch( p->in.left->in.op ){
1332 case FLD:
1333 q = p->in.left->in.left;
1334 /*
1335 * rewrite (lval.fld /= rval); as
1336 * ((*temp).fld = udiv((*(temp = &lval)).fld,rval));
1337 * else the compiler will evaluate lval twice.
1338 */
1339 if( q->in.op == UNARY MUL ){
1340 /* first allocate a temp storage */
1341 temp = talloc();
1342 temp->in.op = OREG;
1343 temp->tn.rval = TMPREG;
1344 temp->tn.lval = BITOOR(freetemp(1));
1345 temp->in.type = INCREF(p->in.type);
1346#ifdef FLEXNAMES
1347 temp->in.name = "";
1348#else
1349 temp->in.name[0] = '\0';
1350#endif
1351 old = q->in.left;
1352 q->in.left = temp;
1353 }
1354 /* fall thru ... */
f2b49199 1355
20018a56
DS
1356 case REG:
1357 case NAME:
1358 case OREG:
1359 /* change ASG OP to a simple OP */
1360 q = talloc();
1361 q->in.op = NOASG p->in.op;
1362 q->in.rall = NOPREF;
1363 q->in.type = p->in.type;
1364 q->in.left = tcopy(p->in.left);
1365 q->in.right = p->in.right;
1366 p->in.op = ASSIGN;
1367 p->in.right = q;
1368 p = q;
1369 f -= 2; /* Note: this depends on the table order */
1370 /* on the right side only - replace *temp with
1371 *(temp = &lval), build the assignment node */
1372 if( old ){
1373 temp = q->in.left->in.left; /* the "*" node */
1374 q = talloc();
1375 q->in.op = ASSIGN;
1376 q->in.left = temp->in.left;
1377 q->in.right = old;
1378 q->in.type = old->in.type;
1379#ifdef FLEXNAMES
1380 q->in.name = "";
f2b49199 1381#else
20018a56 1382 q->in.name[0] = '\0';
f2b49199 1383#endif
20018a56
DS
1384 temp->in.left = q;
1385 }
1386 break;
f2b49199 1387
20018a56
DS
1388 case UNARY MUL:
1389 /* avoid doing side effects twice */
1390 q = p->in.left;
1391 p->in.left = q->in.left;
1392 q->in.op = FREE;
1393 break;
1394
1395 default:
1396 cerror( "hardops: can't compute & LHS" );
1397 }
1398 }
f2b49199 1399
20018a56
DS
1400 /* build comma op for args to function */
1401 q = talloc();
1402 q->in.op = CM;
1403 q->in.rall = NOPREF;
1404 q->in.type = INT;
1405 q->in.left = p->in.left;
1406 q->in.right = p->in.right;
f2b49199
SL
1407 p->in.op = CALL;
1408 p->in.right = q;
1409
1410 /* put function name in left node of call */
1411 p->in.left = q = talloc();
1412 q->in.op = ICON;
1413 q->in.rall = NOPREF;
1414 q->in.type = INCREF( FTN + p->in.type );
1415#ifndef FLEXNAMES
20018a56 1416 strcpy( q->in.name, f->func );
f2b49199 1417#else
20018a56 1418 q->in.name = f->func;
f2b49199
SL
1419#endif
1420 q->tn.lval = 0;
1421 q->tn.rval = 0;
1422
1423 }
1424
1425zappost(p) NODE *p; {
1426 /* look for ++ and -- operators and remove them */
1427
1428 register int o, ty;
1429 register NODE *q;
1430 o = p->in.op;
1431 ty = optype( o );
1432
1433 switch( o ){
1434
1435 case INCR:
1436 case DECR:
1437 q = p->in.left;
1438 p->in.right->in.op = FREE; /* zap constant */
1439 ncopy( p, q );
1440 q->in.op = FREE;
1441 return;
1442
1443 }
1444
1445 if( ty == BITYPE ) zappost( p->in.right );
1446 if( ty != LTYPE ) zappost( p->in.left );
1447}
1448
1449fixpre(p) NODE *p; {
1450
1451 register int o, ty;
1452 o = p->in.op;
1453 ty = optype( o );
1454
1455 switch( o ){
1456
1457 case ASG PLUS:
1458 p->in.op = PLUS;
1459 break;
1460 case ASG MINUS:
1461 p->in.op = MINUS;
1462 break;
1463 }
1464
1465 if( ty == BITYPE ) fixpre( p->in.right );
1466 if( ty != LTYPE ) fixpre( p->in.left );
1467}
1468
1469NODE * addroreg(l) NODE *l;
1470 /* OREG was built in clocal()
1471 * for an auto or formal parameter
1472 * now its address is being taken
1473 * local code must unwind it
1474 * back to PLUS/MINUS REG ICON
1475 * according to local conventions
1476 */
1477{
1478 cerror("address of OREG taken");
1479}
1480
1481# ifndef ONEPASS
1482main( argc, argv ) char *argv[]; {
1483 return( mainp2( argc, argv ) );
1484 }
1485# endif
1486
f1824a4b
SL
1487strip(p) register NODE *p; {
1488 NODE *q;
1489
1490 /* strip nodes off the top when no side effects occur */
1491 for( ; ; ) {
1492 switch( p->in.op ) {
1493 case SCONV: /* remove lint tidbits */
1494 q = p->in.left;
1495 ncopy( p, q );
1496 q->in.op = FREE;
1497 break;
1498 /* could probably add a few more here */
1499 default:
1500 return;
1501 }
1502 }
1503 }
1504
f2b49199 1505myreader(p) register NODE *p; {
f1824a4b 1506 strip( p ); /* strip off operations with no side effects */
f2b49199
SL
1507 walkf( p, hardops ); /* convert ops to function calls */
1508 canon( p ); /* expands r-vals for fileds */
1509 walkf( p, optim2 );
1510 }