|
|
1.1 root 1: #include "gencode.h"
2: #define fieldbotch(p) if(p->in.left->in.op == FLD) {rewritefld(p); longjmp(back, 1);}
3: jmp_buf back;
4: int acnt, Pflag, bbcnt;
5:
6: gencode(p)
7: NODE *p;
8: { NODE *q;
9: ret s;
10: int svtemp, svregvar, i, svbb;
11: extern int bothdebug;
12: svtemp = tmpoff;
13: svregvar = regvar;
14: svbb = ++bbcnt;
15: if(setjmp(back)) {
16: pr("#\treg\t%d\n", ++acnt)/*, prtree(q), putchar('\n')*/;
17: if(acnt > 20) {
18: prtree(q);
19: outpr();
20: tmpoff = svtemp;
21: bbcnt = svbb;
22: uerror("expression too complicated");
23: return;
24: }
25: }
26: else
27: q = copytree(p);
28: buf = bufs[1];
29: prptr = prbuf;
30: if(Pflag && q->in.op != INIT) {
31: pr("#\tincl\tlocprof+%d\n", 4*(svbb+3));
32: }
33: /*printx("#%d ", acnt), prtree(q), printx("\n"), outpr();*/
34: s = doit(q, 0, 0, REGMASK);
35: if(s.flag & FAIL)
36: uerror("codegen failed at top level");
37: acnt = ntree = 0;
38: if(Pflag && q->in.op != INIT)
39: printx("#%d ", svbb), prtree(q), printx("\n");
40: outpr();
41: tmpoff = svtemp;
42: regvar = svregvar;
43: if(M32 && !bothdebug)
44: for(i = 0; i < NRGS; i++)
45: busy[i] = 0;
46: }
47:
48: ret
49: doit(p, flag, dest, regmask)
50: NODE *p;
51: ret dest;
52: { ret s, t, x, y;
53: char *pp;
54: NODE snode, *q;
55: int i, j, svmask = regmask;
56: switch(p->in.op) {
57: default:
58: pr("#\tweird??? %d\n", p->in.op);
59: return(dest);
60: case ASG AND:
61: fieldbotch(p)
62: if(dest.ans && p->in.left->in.op == STAR)
63: longjmp(back, mediumstar(p));
64: flag |= DESTISLEFT;
65: flag &= ~CC;
66: case AND:
67: if((flag & CC)) {
68: if(p->in.left->in.op == CONV && incrsize(p->in.left->in.left) < 4)
69: p->in.left = p->in.left->in.left;
70: if(p->in.right->in.op == CONV
71: && incrsize(p->in.right->in.left) < 4)
72: p->in.right = p->in.right->in.left;
73: }
74: t = doit(p->in.left, VALUE|USED, 0, regmask);
75: if(t.flag & FAIL)
76: return(t);
77: regmask &= ~t.regmask;
78: s = doit(p->in.right, VALUE|USED, 0, regmask);
79: if(s.flag & FAIL)
80: goto binfail;
81: if(flag & CC) {
82: if(incrsize(p->in.left) <= incrsize(p->in.right))
83: i = childtype(p);
84: else
85: i = type(p->in.right);
86: pr("#\tbit%c\t%s,%s\n", i, str(s), str(t));
87: dest.ans = 0;
88: dest.flag = CC;
89: dest.regmask = 0;
90: return(dest);
91: }
92: regmask &= ~s.regmask;
93: #if VAX==1
94: /* p->in.right->in.op == COMPL is a useful special case */
95: if((flag & DESTISLEFT) && dest.ans == 0)
96: dest = x = t;
97: if(dest.ans == 0)
98: if(s.flag & SCRATCH)
99: dest = x = s;
100: else if(t.flag & SCRATCH) {
101: dest = t;
102: x = allocreg(p, regmask);
103: }
104: else
105: dest = x = allocreg(p, regmask);
106: else
107: x = allocreg(p, regmask);
108: if(p->in.right->in.op == ICON) {
109: x = tostack(); /* to get a buf */
110: sprintx(str(x), "$%d", -p->in.right->tn.lval - 1);
111: }
112: else
113: pr("#\tmcom%c\t%s,%s\n", childtype(p), str(s), str(x));
114: if(strcmp(str(t), str(dest)) == 0)
115: pr("#\tbic%c2\t%s,%s\n", childtype(p), str(x), str(dest));
116: else if(flag & DESTISLEFT) {
117: pr("#\tbic%c2\t%s,%s\n", childtype(p), str(x), str(t));
118: if(strcmp(str(t), str(dest))) {
119: x = t;
120: goto movexdest;
121: }
122: }
123: else
124: pr("#\tbic%c3\t%s,%s,%s\n", childtype(p), str(x),
125: str(t), str(dest));
126: dest.flag |= CC;
127: return(dest);
128: #endif
129: case CALL:
130: call:
131: s.flag = funargs(p->in.right, regmask);
132: if(s.flag & FAIL)
133: return(s);
134: i = p->stn.argsize/32;
135: called:
136: s = doit(p->in.left, VALUE|ASADDR|USED, 0, regmask);
137: pp = str(s);
138: aftercall:
139: if(svmask != REGMASK) {
140: s.flag = FAIL;
141: return(s);
142: }
143: x = specialreg(p, regmask);
144: if(M32 && (p->in.op == STCALL || p->in.op == UNARY STCALL))
145: pr("#\tmovaw\t%d(%%fp),%%r2\n", gimmetemp(p->stn.stsize/SZINT));
146: pr(VAX? "#\tcalls\t$%d,%s\n": "#\tcall\t&%d,%s\n", i, pp);
147: if(flag & ASADDR) {
148: strcat(str(x), ")");
149: strshift(str(x), 1);
150: str(x)[0] = '(';
151: }
152: if(dest.ans == 0 && (VAX || !(flag & TOSTACK)))
153: if(flag & DESTISLEFT)
154: dest = doit(p->in.left->in.op == CONV?
155: p->in.left->in.left:
156: p->in.left, 0/* ? */, 0, regmask & ~x.regmask);
157: else
158: return(x);
159: movexdest: /* type(p), not childtype, for a = a % b */
160: if(strcmp(str(x), str(dest)) == 0)
161: return(x);
162: if((flag & TOSTACK) && incrsize(p) == 4)
163: pr("#\tpush%c\t%s\n", type(p), str(x));
164: else if(x.flag & ICON0)
165: pr("#\tclr%c\t%s\n", type(p), str(dest));
166: else if(VAX && isfloat(p) != isfloat(p->in.left)
167: && p->in.op != CALL && p->in.op != UNARY CALL)
168: pr("#\tcvt%c%c\t%s,%s\n", childtype(p), type(p), str(x), str(dest));
169: else if(VAX && (flag & TOSTACK) && (incrsize(p) != 8))
170: pr("#\tcvt%cl\t%s,-(sp)\n", type(p), str(x));
171: else {
172: pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
173: dest = simpler(x, dest);
174: }
175: dest.flag |= CC;
176: return(dest);
177: case CMP:
178: if(p->in.left->in.op == CONV && p->in.right->in.op == CONV
179: && childtype(p->in.left) == childtype(p->in.right)) {
180: p->in.left = p->in.left->in.left;
181: p->in.right = p->in.right->in.left;
182: }
183: else if(p->in.left->in.op == CONV && p->in.right->in.op == ICON
184: && p->in.right->tn.lval >= 0
185: && ((incrsize(p->in.left->in.left) == 1
186: && p->in.right->tn.lval < 128)
187: || (incrsize(p->in.left->in.left) == 2
188: && p->in.right->tn.lval < 32768)))
189: p->in.left = p->in.left->in.left;
190: /* the above rewriting depends on childype being of p->left */
191: s = doit(p->in.left, VALUE|USED, 0, regmask);
192: if(s.flag & FAIL)
193: return(s);
194: regmask &= ~s.regmask;
195: t = doit(p->in.right, VALUE|USED, 0, regmask);
196: if(t.flag & FAIL) {
197: totemp(p, LEFT);
198: longjmp(back, 1);
199: }
200: pr("#\tcmp%c\t%s,%s\n", childtype(p), str(s), str(t));
201: dest.ans = dest.regmask = 0;
202: dest.flag = CC;
203: return(dest);
204: case COMOP: /* qnodes lurking underneath */
205: if(p->in.left->in.op == GENLAB) {
206: if(dest.ans == 0) {
207: dest = allocreg(p, regmask);
208: }
209: t = doit(p->in.left, VALUE|(flag & CC), dest, regmask);
210: }
211: else
212: t = doit(p->in.left, 0, 0, regmask);
213: if(t.flag & FAIL)
214: return(t);
215: s = doit(p->in.right, VALUE|(flag & (USED|CC)), dest, regmask);
216: if(s.flag & FAIL)
217: return(s);
218: if(flag & ASADDR) {
219: dest.ans = 0;
220: i = (s.flag & (ISREG|CANINDIR|SCRATCH));
221: j = s.regmask;
222: buf = str(s);
223: goto convbuf;
224: }
225: return(s);
226: case COMPL:
227: s = doit(p->in.left, VALUE|USED, 0, regmask);
228: if(s.flag & FAIL)
229: return(s);
230: if(dest.ans == 0)
231: if(s.flag & SCRATCH)
232: dest = s;
233: else
234: dest = allocreg(p, regmask & ~s.regmask);
235: pr("#\tmcom%c\t%s,%s\n", childtype(p), str(s), str(dest));
236: dest.flag |= CC;
237: return(dest);
238: case CONV:
239: if(p->in.left->in.op == ASSIGN && p->in.left->in.left->in.op == STAR) {
240: if(dest.ans == 0) {
241: dest = allocreg(p, regmask);
242: s = doit(p->in.left, VALUE|USED, dest, regmask);
243: }
244: else {
245: x = allocreg(p, regmask);
246: s = doit(p->in.left, VALUE|USED, x, regmask & ~x.regmask);
247: }
248: if(s.flag & FAIL) {
249: asgwrite(p->in.left);
250: longjmp(back, 1);
251: }
252: }
253: else
254: s = doit(p->in.left, VALUE|USED, 0, regmask);
255: if(childtype(p) == type(p) && dest.ans == 0)
256: return(s);
257: if(s.flag & FAIL)
258: return(s);
259: if(dest.ans == 0)
260: if(s.flag & SCRATCH)
261: dest = checksize(p, s, regmask);
262: else
263: dest = allocreg(p, regmask);
264: if(isunsigned(p->in.left) && incrsize(p) > incrsize(p->in.left)) {
265: if(type(p) != 'f' && type(p) != 'd')
266: pp = "movz";
267: else { /* uns to float or double */
268: rewriteconv(p);
269: longjmp(back, 1);
270: }
271: }
272: else
273: pp = VAX? "cvt": "movb";
274: if(isfloat(p) != isfloat(p->in.left))
275: goto cvtop;
276: if(incrsize(p) < incrsize(p->in.left)) {
277: if(isfloat(p))
278: goto cvtop;
279: pr("#\tmov%c\t%s,%s\n", type(p), str(s), str(dest));
280: dest = simpler(s, dest);
281: }
282: else if(incrsize(p) > incrsize(p->in.left))
283: cvtop:
284: pr("#\t%s%c%c\t%s,%s\n", pp, childtype(p), type(p), str(s), str(dest));
285: else { /* types were the same, but dest.ans != 0 */
286: pr("#\tmov%c\t%s,%s\n", type(p), str(s), str(dest));
287: dest = simpler(s, dest);
288: }
289: if(M32 && (flag & TOSTACK))
290: pr("#\tpushw\t%s\n", str(dest));
291: dest.flag |= CC;
292: return(dest);
293: case DECR:
294: i = -1;
295: pp = "sub";
296: incrop:
297: if(p->in.type == TFLOAT)
298: uerror("no float ++/--");
299: fieldbotch(p)
300: /* if the dest uses regs, it may be from a qnode, so that reg
301: * shouldn't be used (i?*a->b++:x()) where b has offset > 0
302: */
303: s = doit(p->in.left, USED, 0, dest.ans? regmask & ~dest.regmask: regmask);
304: if(s.flag & FAIL)
305: return(s);
306: t = doit(p->in.right, 0, 0, 0);
307: if(flag & VALUE) {
308: if(dest.ans == 0)
309: dest = allocreg(p, regmask & ~s.regmask);
310: pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(dest));
311: if(t.flag & ICON1) {
312: if(i == 1)
313: pp = "inc";
314: else
315: pp = "dec";
316: pr("#\t%s%c\t%s\n", pp, childtype(p), str(s));
317: }
318: else
319: pr("#\t%s%c2\t%s,%s\n", pp, childtype(p),
320: str(t), str(s));
321: if(flag & ASADDR) {
322: if(dest.flag & ISREG) {
323: sprintx(buf, "0(%s)", str(dest));
324: done(dest, CANINDIR, dest.regmask);
325: }
326: if(dest.flag & CANINDIR) {
327: sprintx(buf, "*%s", str(dest));
328: done(dest, 0, dest.regmask);
329: }
330: uerror("weird asaddr in incrop");
331: }
332: dest.flag &= ~CC;
333: return(dest);
334: }
335: if(t.flag & ICON1) {
336: if(i == 1)
337: pp = "inc";
338: else
339: pp = "dec";
340: pr("#\t%s%c\t%s\n", pp, childtype(p), str(s));
341: }
342: else
343: pr("#\t%s%c2\t%s,%s\n", pp, childtype(p), str(t), str(s));
344: if(dest.ans) {
345: x = s;
346: goto movexdest;
347: }
348: s.flag &= ~CC;
349: return(s);
350: case ASG DIV:
351: fieldbotch(p)
352: if(rewriteasgop(p))
353: goto assign;
354: flag |= DESTISLEFT;
355: case DIV:
356: /* trees wrong: uns/=int and int/=uns */
357: if(!isunsigned(p->in.right) && !isunsigned(p->in.left)) {
358: pp = "div";
359: goto binop;
360: }
361: pp = "udiv";
362: #if M32==1
363: goto binop;
364: #else if VAX==1
365: unsdiv:
366: if(incrsize(p->in.right) != 4) {
367: snode.in.op = CONV;
368: snode.in.left = p->in.right;
369: snode.in.type = TULONG;
370: s = doit(&snode, VALUE|TOSTACK, tostack(), regmask);
371: }
372: else
373: s = doit(p->in.right, TOSTACK, tostack(), regmask);
374: if(s.flag & FAIL)
375: return(s);
376: regmask &= ~s.regmask;
377: if(incrsize(p->in.left) != 4) {
378: snode.in.op = CONV;
379: snode.in.left = p->in.left;
380: snode.in.type = TULONG;
381: t = doit(&snode, VALUE|TOSTACK, tostack(), regmask);
382: }
383: else
384: t = doit(p->in.left, TOSTACK, tostack(), regmask);
385: if(t.flag & FAIL) {
386: if(dest.ans || svmask != REGMASK) {
387: t = doit(p->in.left, VALUE|TOSTACK, tostack(), svmask);
388: if(t.flag & FAIL)
389: return(t);
390: }
391: totemp(p, RIGHT);
392: longjmp(back, 1);
393: }
394: i = 2;
395: goto aftercall;
396: #endif
397: case ASG ER:
398: fieldbotch(p)
399: flag |= DESTISLEFT;
400: case ER:
401: pp = "xor";
402: binop:
403: if((flag & DESTISLEFT) && dest.ans && p->in.left->in.op == STAR)
404: longjmp(back, mediumstar(p));
405: t = doit(p->in.left, VALUE|USED, 0, regmask);
406: if(t.flag & FAIL) {
407: return(t);
408: }
409: regmask &= ~t.regmask;
410: s = doit(p->in.right, VALUE|USED, 0, regmask);
411: if(s.flag & FAIL) {
412: binfail:
413: if(dest.ans || svmask != REGMASK) {
414: s = doit(p->in.right, VALUE|USED, 0, svmask);
415: if(s.flag & FAIL)
416: return(s);
417: }
418: /* *foo op= expr requires care */
419: if((flag & DESTISLEFT) && p->in.left->in.op == STAR)
420: totemp(p->in.left, LEFT);
421: else
422: totemp(p, LEFT);
423: longjmp(back, 1);
424: }
425: if(type(p) != childtype(p)) {
426: x = allocreg(p, regmask);
427: pr("#\t%s%c3\t%s,%s,%s\n", pp, childtype(p), str(s),
428: str(t), str(x));
429: if(dest.ans == 0)
430: dest = x;
431: if(!isfloat(p) && !isfloat(p->in.left)
432: && incrsize(p) < incrsize(p->in.left)) {
433: pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
434: dest = simpler(x, dest);
435: }
436: else
437: pr("#\tcvt%c%c\t%s,%s\n", childtype(p), type(p),
438: str(x), str(dest));
439: dest.flag |= CC;
440: return(dest);
441: }
442: if(dest.ans == 0)
443: if((t.flag & SCRATCH) || (flag & DESTISLEFT)) {
444: twoop:
445: dest = t;
446: if(*pp == 'a' && (s.flag & ICON1))
447: pr("#\tinc%c\t%s\n", childtype(p), str(t));
448: else if(*pp == 's' && (s.flag & ICON1))
449: pr("#\tdec%c\t%s\n", childtype(p), str(t));
450: else
451: pr("#\t%s%c2\t%s,%s\n", pp, childtype(p),
452: str(s), str(t));
453: if(flag & ASADDR)
454: goto binopaddr;
455: if(flag & TOSTACK)
456: pr("#\tpush%c\t%s\n", type(p), str(t));
457: dest.flag |= CC;
458: return(dest);
459: }
460: else if(s.flag & SCRATCH)
461: dest = s;
462: else
463: dest = allocreg(p, regmask);
464: if(dest.ans && (flag & DESTISLEFT)) {
465: pr("#\t%s%c2\t%s,%s\n", pp, childtype(p), str(s), str(t));
466: x = t;
467: goto movexdest;
468: }
469: if((dope[p->in.op] & (COMMFLG|MULFLG)) && strcmp(str(s), str(dest)) == 0) {
470: dest = s;
471: s = t;
472: t = dest;
473: goto twoop;
474: }
475: if(strcmp(str(t), str(dest)) == 0)
476: goto twoop;
477: pr("#\t%s%c3\t%s,%s,%s\n", pp, childtype(p), str(s), str(t), str(dest));
478: if(M32 && (flag & TOSTACK)) {
479: pr("#\tpushw\t%s\n", str(dest));
480: return(dest);
481: }
482: binopaddr:
483: if(flag & ASADDR) {
484: if(dest.flag & ISREG) {
485: strcat(str(dest), ")");
486: strshift(str(dest), 1);
487: str(dest)[0] = '(';
488: return(dest);
489: }
490: if(dest.flag & CANINDIR) {
491: strshift(str(dest), 1);
492: str(dest)[0] = '*';
493: dest.flag &= ~CANINDIR;
494: return(dest);
495: }
496: dest.flag = FAIL; /* doubtful */
497: return(dest);
498: }
499: dest.flag |= CC;
500: return(dest);
501: case FLD:
502: /* this is rvalues */
503: s = doit(p->in.left, USED, 0, regmask);
504: if(s.flag & FAIL)
505: return(s);
506: if(dest.ans == 0)
507: dest = allocreg(p, regmask);
508: if((s.flag & INDEX) && p->in.left->in.op == STAR
509: && incrsize(p->in.left) != 1) {
510: /* over-enthusiastic use of index mode */
511: if(dest.flag & SCRATCH)
512: x = dest;
513: else
514: x = allocreg(p, regmask);
515: pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(x));
516: s = x;
517: }
518: #if VAX==1
519: pr("#\text%sv\t$%d,$%d,%s,%s\n", isunsigned(p->in.left)? "z": "",
520: p->tn.rval/64, p->tn.rval%64, str(s), str(dest));
521: #else if M32==1
522: i = p->tn.rval % 64;
523: j = 32 - p->tn.rval/64 - i;
524: pr("#\textzv\t&%d,&%d,%s,%s\n", j, i, str(s), str(dest));
525: #endif
526: dest.flag |= CC;
527: return(dest);
528: case GENBR:
529: if(p->in.left->in.op == CONV)
530: p->in.left = p->in.left->in.left;
531: s = doit(p->in.left, CC|VALUE|USED, 0, regmask);
532: pp = genjmp(p->bn.lop);
533: if(s.flag & CC)
534: pr("#\t%s\t", pp);
535: else if(VAX)
536: pr("#\ttst%c\t%s\n#\t%s\t", childtype(p), str(s), pp);
537: else if(M32)
538: pr("#\tcmp%c\t%s,&0\n#\t%s\t", childtype(p), str(s), pp);
539: pr(VAX? "L%d\n": ".L%d\n", p->bn.label);
540: s.flag |= CC; /* ?? */
541: if(Pflag) {
542: ++bbcnt;
543: pr("#\tincl\tlocprof+%d\n", 4*(bbcnt+3));
544: }
545: return(s);
546: case GENLAB:
547: s = doit(p->in.left, flag, dest, regmask);
548: pr(VAX? "#L%d:\n": "#.L%d:\n", p->bn.label);
549: if(M32 && (flag & TOSTACK))
550: pr("#\tpushw\t%s\n", str(s));
551: if(Pflag) {
552: ++bbcnt;
553: pr("#\tincl\tlocprof+%d\n", 4*(bbcnt+3));
554: }
555: return(s);
556: case GENUBR:
557: s = doit(p->in.left, flag & CC, dest, regmask);
558: if((flag & CC) && !(s.flag & CC))
559: pr("#\ttst%c\t%s\n", childtype(p), str(s));
560: pr(VAX? "#\tjbr\tL%d\n": "#\tjmp\t.L%d\n", p->bn.label);
561: return(s);
562: case ICON:
563: if(p->tn.name)
564: if(p->tn.lval)
565: sprintx(buf, "%s+%d", p->tn.name, p->tn.lval);
566: else
567: sprintx(buf, "%s", p->tn.name);
568: else
569: sprintx(buf, "%d", p->tn.lval);
570: if(!(flag & ASADDR)) {
571: strshift(buf, 1);;
572: buf[0] = VAX? '$': '&';
573: }
574: i = 0;
575: if(VAX && p->tn.name == 0)
576: if(p->tn.lval == 0)
577: i = ICON0;
578: else if(p->tn.lval == 1)
579: i = ICON1;
580: j = 0;
581: convbuf: /* the cookie is in buf */
582: if(dest.ans == 0 && !(flag & TOSTACK)) {
583: if(p->in.op == ICON || !(flag & ASADDR)) {
584: done(s, i, j);
585: }
586: if(i & CANINDIR) {
587: strshift(buf, 1);
588: buf[0] = '*';
589: done(s, i & ~CANINDIR, j);
590: }
591: if(i & ISREG) {
592: strcat(buf, ")");
593: strshift(buf, 1);
594: buf[0] = '(';
595: done(s, i, j);
596: }
597: pp = buf;
598: buf += BUF;
599: s = allocreg(p, regmask);
600: pr("#\tmov%c\t%s,%s\n", type(p), pp, str(s));
601: flag &= ~ASADDR;
602: goto inreg;
603: }
604: if(flag & TOSTACK)
605: if(incrsize(p) == 4)
606: pr(VAX? "#\tpushl\t%s\n": "#\tpushw\t%s\n", buf);
607: else if(incrsize(p) == 8)
608: pr("#\tmovd\t%s,%s\n", buf, str(dest));
609: else
610: pr("#\tcvt%cl\t%s,%s\n", type(p), buf, str(dest));
611: else if(i & ICON0)
612: pr("#\tclr%c\t%s\n", type(p), str(dest));
613: else {
614: pr("#\tmov%c\t%s,%s\n", type(p), buf, str(dest));
615: if(!(dest.flag & INDEX) || !index(str(dest), '+')
616: && !index(str(dest), '-'))
617: ;
618: else if(!(i & INDEX) || !index(buf, '+')
619: && !index(buf, '-')) {
620: done(s, (i|CC), j);
621: }
622: else
623: dest.flag |= USED;
624: }
625: dest.flag |= CC;
626: return(dest);
627: case INCR:
628: i = 1;
629: pp = "add";
630: goto incrop;
631: case INIT: /* knows it is ICON */
632: s = doit(p->in.left, ASADDR, 0, 0);
633: pr(VAX? "#\t.long\t%s\n": "#\t.word\t%s\n", str(s));
634: return(dest);
635: case ASG LS:
636: if(VAX && incrsize(p) != 4)
637: lsconv(p);
638: if(rewriteasgop(p))
639: goto assign;
640: fieldbotch(p)
641: flag |= DESTISLEFT;
642: if(dest.ans && p->in.left->in.op == STAR)
643: longjmp(back, mediumstar(p));
644: case LS: /* stupid vax */
645: #if M32==1
646: pp = "LLS";
647: shiftop:
648: #endif
649: if(VAX && incrsize(p) != 4)
650: lsconv(p);
651: s = doit(p->in.left, VALUE|USED, 0, regmask);
652: if(s.flag & FAIL)
653: return(s);
654: regmask &= ~s.regmask;
655: t = doit(p->in.right, VALUE|USED, 0, regmask);
656: if(t.flag & FAIL)
657: goto binfail;
658: if(dest.ans == 0)
659: if((s.flag & SCRATCH) || (flag & DESTISLEFT))
660: dest = s;
661: else
662: dest = allocreg(p, regmask);
663: #if VAX==1
664: if(incrsize(p) != 4) { /* stupid vax */
665: x = allocreg(p, regmask);
666: pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(x));
667: pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(dest));
668: if(flag & DESTISLEFT)
669: pr("#\tmovl\t%s,%s\n", str(x), str(s));
670: dest.flag |= CC;
671: return(dest);
672: }
673: if(p->in.right->in.op == ICON && (i = p->in.right->tn.lval) <= 4
674: && (dest.flag & ISREG)) {
675: if(strcmp(str(s), str(dest))) {
676: i--;
677: pr("#\taddl3\t%s,%s,%s\n", str(s), str(s), str(dest));
678: }
679: while(i-- > 0)
680: pr("#\taddl2\t%s,%s\n", str(dest), str(dest));
681: }
682: else if(flag & DESTISLEFT)
683: pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(s));
684: else
685: pr("#\tashl\t%s,%s,%s\n", str(t), str(s), str(dest));
686: if((flag & DESTISLEFT) && strcmp(str(dest), str(s)))
687: pr("#\tmovl\t%s,%s\n", str(s), str(dest));
688: #else if M32==1
689: pr("#\t%s%c3\t%s,%s,%s\n", pp, childtype(p) + UP, str(t), str(s),
690: str(dest));
691: if(flag & TOSTACK)
692: pr("#\tpush%c\t%s\n", type(p), str(dest));
693: #endif
694: dest.flag |= CC;
695: return(dest);
696: case ASG MINUS:
697: fieldbotch(p)
698: if(rewriteasgop(p))
699: goto assign;
700: flag |= DESTISLEFT;
701: case MINUS:
702: pp = "sub";
703: /* you won't believe this: type x[], *y where type is shorter than
704: * int, generates subx $_x,y which the assembler barfs on.
705: * instead, generate crummy code (stupid assembler)
706: */
707: if(incrsize(p) < 4) {
708: if(p->in.left->in.op == ICON && p->in.left->tn.name) {
709: p->in.left->in.type = TINT;
710: totemp(p, LEFT);
711: }
712: if(p->in.right->in.op == ICON && p->in.right->tn.name) {
713: p->in.right->in.type = TINT;
714: totemp(p, RIGHT);
715: }
716: }
717: goto binop;
718: case ASG MOD:
719: fieldbotch(p)
720: if(rewriteasgop(p))
721: goto assign;
722: if(dest.ans && p->in.left->in.op == STAR)
723: longjmp(back, mediumstar(p));
724: flag |= DESTISLEFT;
725: case MOD:
726: #if M32==1
727: if(isunsigned(p->in.right) || isunsigned(p->in.left))
728: pp = "umod";
729: else
730: pp = "mod";
731: goto binop;
732: #else if VAX==1
733: if(isunsigned(p->in.right) || isunsigned(p->in.left)) {
734: pp = "urem";
735: goto unsdiv;
736: }
737: s = doit(p->in.left, VALUE|USED, 0, regmask);
738: if(s.flag & FAIL)
739: return(s);
740: regmask &= ~s.regmask;
741: t = doit(p->in.right, VALUE|USED, 0, regmask);
742: if(t.flag & FAIL)
743: goto binfail;
744: regmask &= ~t.regmask;
745: x = allocreg(p, regmask);
746: pr("#\tdiv%c3\t%s,%s,%s\n", childtype(p), str(t), str(s), str(x));
747: pr("#\tmul%c2\t%s,%s\n", childtype(p), str(t), str(x));
748: pr("#\tsub%c3\t%s,%s,%s\n", childtype(p), str(x), str(s), str(x));
749: if(dest.ans)
750: goto movexdest;
751: if(flag & DESTISLEFT) {
752: dest = s;
753: goto movexdest;
754: }
755: x.flag |= CC;
756: return(x);
757: #endif
758: case ASG MUL:
759: fieldbotch(p)
760: if(rewriteasgop(p))
761: goto assign;
762: flag |= DESTISLEFT;
763: case MUL:
764: pp = "mul";
765: goto binop;
766: case NAME: /* ASADDR? */
767: if(p->tn.lval && p->tn.name)
768: sprintx(buf, "%s+%d", p->tn.name, p->tn.lval);
769: else if(p->tn.name)
770: sprintx(buf, "%s", p->tn.name);
771: else if(p->tn.lval)
772: sprintf(buf, "%d", p->tn.lval);
773: else
774: sprintx(buf, "0");
775: j = 0;
776: i = CANINDIR;
777: goto convbuf;
778: case ASG OR:
779: fieldbotch(p)
780: flag |= DESTISLEFT;
781: case OR:
782: pp = VAX? "bis": "or";
783: goto binop;
784: case ASG PLUS:
785: fieldbotch(p)
786: if(rewriteasgop(p))
787: goto assign;
788: flag |= DESTISLEFT;
789: case PLUS:
790: pp = "add";
791: goto binop;
792: case REG:
793: sprintx(buf, "%s", regnames[p->tn.rval]);
794: j = 0;
795: i = ISREG;
796: if(p->tn.lval == 1)
797: i |= SCRATCH;
798: goto convbuf;
799: case RNODE: case SNODE:
800: x = specialreg(p, 3);
801: x.regmask = 0;
802: if(dest.ans)
803: goto movexdest;
804: return(x);
805: case QNODE:
806: return(specialreg(p, regmask));
807: case ASG RS:
808: fieldbotch(p)
809: if(VAX && incrsize(p) != 4)
810: lsconv(p);
811: if(rewriteasgop(p))
812: goto assign;
813: flag |= DESTISLEFT;
814: case RS: /* all right shifts are unsigned */
815: if(incrsize(p) != 4)
816: lsconv(p);
817: #if M32==1
818: pp = "LRS";
819: goto shiftop;
820: #else if VAX==1
821: s = doit(p->in.left, VALUE|USED, 0, regmask);
822: if(s.flag & FAIL)
823: return(s);
824: if(p->in.left->in.op == ICON ||
825: (s.flag & INDEX) && p->in.left->in.op == STAR
826: && incrsize(p->in.left) != 1 ||
827: (s.flag & AUTO) && incrsize(p->in.left) != 1) {
828: /* over-enthusiastic use of index mode */
829: /* 12 >> i generates a byte immediate */
830: if((s.flag & INDEX) && (flag & DESTISLEFT)) {/* *a++ >>= 1 */
831: lsconv(p); /* not best */
832: longjmp(back, 1);
833: }
834: if((flag & DESTISLEFT) && dest.ans == 0) {
835: dest = s;
836: regmask &= ~s.regmask;
837: }
838: if(dest.flag & SCRATCH)
839: x = dest;
840: else
841: x = allocreg(p, regmask);
842: pr("#\tmovl\t%s,%s\n", str(s), str(x));
843: s = x;
844: }
845: regmask &= ~s.regmask;
846: if(dest.ans == 0)
847: if((flag & DESTISLEFT) || (s.flag & SCRATCH))
848: dest = s;
849: else
850: dest = allocreg(p, regmask);
851: dest.flag |= CC;
852: regmask &= ~dest.regmask;
853: if(incrsize(p) != 4)
854: x = allocreg(p, regmask);
855: else
856: x = dest;
857: if(p->in.right->in.op == ICON && (i = p->in.right->tn.lval) >= 0) {
858: pr("#\textzv\t$%d,$%d,%s,%s\n", i, 32 - i, str(s), str(x));
859: goto movexdest;
860: }
861: t = doit(p->in.right, VALUE|USED, 0, regmask);
862: if(t.flag & FAIL)
863: goto binfail;
864: y = allocreg(p, regmask & ~t.regmask);
865: pr("#\tsubl3\t%s,$32,%s\n", str(t), str(y));
866: pr("#\textzv\t%s,%s,%s,%s\n", str(t), str(y), str(s), str(x));
867: goto movexdest;
868: #endif
869: case STAR:
870: switch(p->in.left->in.op) {
871: case ICON: /* as in foo((a, a)), where a is a struct */
872: s = doit(p->in.left, VALUE, 0, regmask);
873: sprintx(buf, "%s", str(s)+1);
874: i = j = 0;
875: goto convbuf;
876: case VAUTO:
877: case VPARAM:
878: case NAME:
879: s = doit(p->in.left, VALUE, 0, regmask);
880: sprintx(buf, "*%s", str(s));
881: j = i = 0;
882: goto convbuf;
883: case REG:
884: s = doit(p->in.left, VALUE, 0, regmask);
885: inreg:
886: if(s.flag & ISREG) {
887: sprintx(buf, VAX? "(%s)": "0(%s)", str(s));
888: j = s.regmask;
889: i = CANINDIR;
890: goto convbuf;
891: }
892: else if(s.flag & CANINDIR) {
893: sprintx(buf, "*%s", str(s));
894: j = s.regmask;
895: i = 0;
896: goto convbuf;
897: }
898: else {
899: s.flag = FAIL;
900: return(s);
901: }
902: }
903: q = p->in.left;
904: if(VAX && q->in.op == INCR && !(flag & INDEX)
905: && q->in.right->in.op == ICON && q->in.left->in.op == REG
906: && incrsize(p) == (int) q->in.right->tn.lval) {
907: s = doit(q->in.left, VALUE, 0, regmask);
908: sprintx(buf, "(%s)+", str(s));
909: i = INDEX|AUTO;
910: j = s.regmask;
911: goto convbuf;
912: }
913: if(VAX && q->in.op == PLUS && q->in.left->in.op == LS
914: && !(flag & INDEX)
915: && q->in.left->in.right->in.op == ICON
916: && shiftsize(p) == (int) q->in.left->in.right->tn.lval) {
917: s = doit(q->in.left->in.left, VALUE|USED, 0, regmask);
918: if(s.flag & FAIL)
919: return(s);
920: regmask &= ~s.regmask;
921: if(!(s.flag & ISREG)) {
922: x = allocreg(p, regmask);
923: pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
924: regmask |= s.regmask;
925: regmask &= ~x.regmask;
926: s = x;
927: if(!(s.flag & ISREG)) {
928: s.flag = FAIL;
929: return(s);
930: }
931: }
932: t = doit(q->in.right, ASADDR|USED, 0, regmask);
933: sprintx(buf, "%s[%s]", str(t), str(s));
934: i = INDEX;
935: j = s.regmask | t.regmask;
936: goto convbuf;
937: }
938: if(q->in.op == PLUS && q->in.right->in.op == ICON) {
939: s = doit(q->in.left, VALUE|USED, 0, regmask);
940: if(s.flag & FAIL)
941: return(s);
942: if(!(s.flag & ISREG)) {
943: x = allocreg(p, regmask);
944: pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
945: s = x;
946: if(!(s.flag & ISREG)) {
947: s.flag = FAIL;
948: return(s);
949: }
950: }
951: regmask &= ~s.regmask;
952: t = doit(q->in.right, ASADDR|USED, 0, regmask);
953: sprintx(buf, "%s(%s)", str(t), str(s));
954: i = CANINDIR;
955: j = s.regmask;
956: goto convbuf;
957: }
958: if(q->in.op == MINUS && q->in.right->in.op == ICON) {
959: s = doit(q->in.left, VALUE|USED, 0, regmask);
960: if(s.flag & FAIL)
961: return(s);
962: if(!(s.flag & ISREG)) {
963: x = allocreg(p, regmask);
964: pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
965: s = x;
966: if(!(s.flag & ISREG)) {
967: s.flag = FAIL;
968: return(s);
969: }
970: }
971: regmask &= ~s.regmask;
972: sprintx(buf, "%d(%s)", -q->in.right->tn.lval, str(s));
973: i = CANINDIR;
974: j = s.regmask;
975: goto convbuf;
976: }
977: if(VAX && q->in.op == ASG MINUS && !(flag & (INDEX|USED))
978: && q->in.right->in.op == ICON && q->in.left->in.op == REG
979: && incrsize(p) == (int) q->in.right->tn.lval) {
980: s = doit(q->in.left, VALUE, 0, regmask);
981: sprintx(buf, "-(%s)", str(s));
982: i = INDEX|AUTO;
983: j = s.regmask;
984: goto convbuf;
985: }
986: if(VAX && q->in.op == PLUS && q->in.left->in.op == REG
987: && !(flag & INDEX) && q->in.right->in.op == REG
988: && incrsize(p) == 1) {
989: sprintx(buf, "(r%d)[r%d]", q->in.right->tn.rval,
990: q->in.left->tn.rval);
991: i = INDEX;
992: j = 0;
993: goto convbuf;
994: }
995: s = doit(p->in.left, VALUE|USED, 0, regmask);
996: if(s.flag & FAIL)
997: return(s);
998: regmask &= ~s.regmask;
999: if(s.flag & CANINDIR) {
1000: sprintx(buf, "*%s", str(s));
1001: i = 0;
1002: j = s.regmask;
1003: goto convbuf;
1004: }
1005: if(!(s.flag & ISREG)) {
1006: x = allocreg(p, regmask);
1007: pr("#\tmov%c\t%s,%s\n", childtype(q), str(s), str(x));
1008: regmask |= s.regmask;
1009: regmask &= ~x.regmask;
1010: s = x;
1011: }
1012: if(!(s.flag & ISREG)) {
1013: s.flag = FAIL;
1014: return(s);
1015: }
1016: sprintx(buf, VAX? "(%s)": "0(%s)", str(s));
1017: i = 0;
1018: j = s.regmask;
1019: goto convbuf;
1020: case STASG:
1021: if(regmask != REGMASK) {
1022: s.flag = FAIL;
1023: return(s);
1024: }
1025: if(p->stn.stsize/8 == 4) {
1026: i = VAX? 'l': 'w';
1027: stasg:
1028: s = doit(p->in.left, VALUE|ASADDR|USED, 0, regmask);
1029: if(s.flag & FAIL)
1030: return(s);
1031: regmask &= ~s.regmask;
1032: t = doit(p->in.right, VALUE|ASADDR|USED, 0, regmask);
1033: if(t.flag & FAIL) {
1034: totemp(p, LEFT);
1035: longjmp(back, 1);
1036: }
1037: pr("#\tmov%c\t%s,%s\n", i, str(t), str(s));
1038: s.regmask = s.flag = 0;
1039: return(simpler(t, s));
1040: }
1041: else if(VAX && p->stn.stsize/8 == 8) {
1042: i = 'q';
1043: goto stasg;
1044: }
1045: #if VAX==1
1046: s = doit(p->in.right, VALUE|USED, 0, regmask);
1047: if(s.flag & INDEX) {
1048: /* over-enthusiastic use of index mode */
1049: x = allocreg(p, regmask);
1050: pr("#\tmovl\t%s,%s\n", str(s), str(x));
1051: s = x;
1052: }
1053: regmask &= ~s.regmask;
1054: t = doit(p->in.left, VALUE|USED, 0, regmask);
1055: if(t.flag & FAIL) {
1056: totemp(p, RIGHT);
1057: longjmp(back, 1);
1058: }
1059: if(t.flag & INDEX) {
1060: /* over-enthusiastic use of index mode */
1061: x = allocreg(p, regmask);
1062: pr("#\tmovl\t%s,%s\n", str(t), str(x));
1063: t = x;
1064: }
1065: t = indirit(t);
1066: if(t.flag & FAIL) {
1067: if(p->in.left->in.op != STAR)
1068: uerror("codegen failure in struct asg");
1069: totemp(p->in.left, LEFT);
1070: longjmp(back, 1);
1071: }
1072: if(p->in.right->in.op == STASG) { /* secret knowledge */
1073: pr("#\tsubl2\t$%d,r3\n", p->stn.stsize/8);
1074: pr("#\tmovc3\t$%d,(r3),%s\n", p->stn.stsize/8, str(t));
1075: }
1076: else {
1077: s = indirit(s);
1078: if(s.flag & FAIL) {
1079: if(p->in.right->in.op != STAR)
1080: uerror("codgen fail in stasg");
1081: totemp(p->in.right, LEFT);
1082: longjmp(back, 1);
1083: }
1084: pr("#\tmovc3\t$%d,%s,%s\n", p->stn.stsize/8, str(s), str(t));
1085: }
1086: t.regmask = t.flag = 0;
1087: #else if M32==1
1088: x = allocreg(p, regmask); /* gets reg 0 */
1089: s = doit(p->in.right, VALUE, x, regmask);
1090: regmask &= ~x.regmask;
1091: y = allocreg(p, regmask); /* gets reg 1 */
1092: i = p->stn.stsize/32;
1093: if(p->in.right->in.op == STASG && i >= 7) { /* secret knowledge */
1094: pr("#\tsubw3\t&%d,%%r1,%%r0\n", p->stn.stsize/8);
1095: }
1096: t = doit(p->in.left, VALUE, y, regmask);
1097: if(t.flag & FAIL)
1098: stasgrewrite(p);
1099: if(i >= 7) {
1100: pr("#\tmovw\t&%d,%%r2\n", i);
1101: pr("#\tMOVBLW\n");
1102: }
1103: else
1104: while(--i >= 0)
1105: pr("#\tmovw\t%d(%r0),%d(%r1)\n", 4 * i, 4 * i);
1106: #endif
1107: return(t);
1108: case STCALL:
1109: goto call;
1110: case VAUTO:
1111: sprintx(buf, "%d(%s)", p->tn.lval, frameptr);
1112: j = 0;
1113: i = CANINDIR;
1114: goto convbuf;
1115: case VPARAM:
1116: sprintx(buf, "%d(%s)", p->tn.lval, argptr);
1117: j = 0;
1118: i = CANINDIR;
1119: goto convbuf;
1120: case UNARY AND:
1121: s = doit(p->in.left, USED, 0, regmask);
1122: if(s.flag & FAIL)
1123: return(s);
1124: regmask &= ~s.regmask;
1125: if(dest.ans == 0) {
1126: dest = allocreg(p, regmask);
1127: }
1128: if(s.flag & ISREG) {
1129: x = alloctmp(p);
1130: pr("#\tmov%c\t%s,%s\n", childtype(p), str(s), str(x));
1131: s = x;
1132: }
1133: if(flag & TOSTACK)
1134: pr(VAX? "#\tpushal\t%s\n": "#\tpushaw\t%s\n", str(s));
1135: else
1136: pr("#\tmova%c\t%s,%s\n", type(p), str(s), str(dest));
1137: if(flag & ASADDR) {
1138: if(dest.flag & ISREG) {
1139: strcat(str(dest), ")");
1140: strshift(str(dest), 1);
1141: str(dest)[0] = '(';
1142: }
1143: else {
1144: strshift(str(dest), 1);
1145: str(dest)[0] = '*';
1146: }
1147: }
1148: return(dest);
1149: case UNARY CALL:
1150: i = 0;
1151: goto called;
1152: case UNARY MINUS:
1153: s = doit(p->in.left, VALUE|USED, 0, regmask);
1154: if(s.flag & FAIL)
1155: return(s);
1156: if(dest.ans == 0)
1157: if(s.flag & SCRATCH)
1158: dest = s;
1159: else
1160: dest = allocreg(p, regmask & ~s.regmask);
1161: pr("#\tmneg%c\t%s,%s\n", childtype(p), str(s), str(dest));
1162: dest.flag |= CC;
1163: return(dest);
1164: case UNARY STCALL:
1165: i = 0;
1166: goto called;
1167: case ASSIGN:
1168: assign:
1169: if(p->in.left->in.op == QNODE && dest.ans) {
1170: s = doit(p->in.right, VALUE|(flag&USED? USED: 0),
1171: dest, regmask);
1172: return(s);
1173: }
1174: if(p->in.left->in.op == RNODE || p->in.left->in.op == SNODE) {
1175: s = doit(p->in.right, VALUE|(flag&USED? USED: 0),
1176: dest, regmask);
1177: if(s.flag & FAIL)
1178: return(s);
1179: x = s;
1180: dest = doit(p->in.left, USED, 0, 0);
1181: goto movexdest;
1182: }
1183: if(p->in.left->in.op == FLD) {
1184: s = doit(p->in.left->in.left, INDEX, 0, regmask);
1185: regmask &= ~s.regmask;
1186: if(p->in.right->in.op == ASSIGN) {
1187: x = allocreg(p->in.right, regmask);
1188: t = doit(p->in.right, VALUE|USED, x, regmask & ~x.regmask);
1189: }
1190: else
1191: t = doit(p->in.right, VALUE|USED, 0, regmask);
1192: if(t.flag & FAIL) {
1193: totemp(p->in.left, LEFT);
1194: longjmp(back, 1);
1195: }
1196: i = VAX? '$': '&';
1197: pr("#\tinsv\t%s,%c%d,%c%d,%s\n", str(t), i,
1198: p->in.left->tn.rval/64, i,
1199: p->in.left->tn.rval % 64, str(s));
1200: if(dest.ans)
1201: pr("#\tmovl\t%s,%s\n", str(t), str(dest));
1202: t.flag |= CC;
1203: return(t);
1204: }
1205: if(dest.ans && p->in.left->in.op == STAR) {
1206: if(dest.flag & SCRATCH)
1207: x = dest;
1208: else
1209: x = allocreg(p, regmask);
1210: s = doit(p->in.right, VALUE|USED, x, regmask);
1211: if(s.flag & FAIL)
1212: return(s);
1213: regmask &= ~s.regmask;
1214: t = doit(p->in.left, USED, 0, regmask);
1215: if(t.flag & FAIL) {
1216: /* did we fail because of a dest, or was it us? */
1217: if(dest.ans || svmask != REGMASK) {
1218: t = doit(p->in.left, USED, 0, svmask);
1219: if(t.flag & FAIL) {
1220: return(t);
1221: }
1222: starasg(p);
1223: }
1224: else
1225: asgwrite(p);
1226: longjmp(back, 1);
1227: }
1228: pr("#\tmov%c\t%s,%s\n", type(p), str(x), str(t));
1229: if(strcmp(str(x), str(dest)) == 0) {
1230: dest.flag |= CC;
1231: return(dest);
1232: }
1233: goto movexdest;
1234: }
1235: t = doit(p->in.left, USED, 0, regmask);
1236: regmask &= ~t.regmask;
1237: if(p->in.right->in.op == GENLAB)
1238: extracheck(p); /* slightly worse code in usual case */
1239: s = doit(p->in.right, VALUE, t, regmask);
1240: if(s.flag & NOGOOD) {
1241: /* did we fail because of a dest, or was it us? */
1242: if(s.flag & FAIL) {
1243: if(dest.ans || svmask != REGMASK) {
1244: s = doit(p->in.right, VALUE, t, svmask);
1245: if(s.flag & FAIL) {
1246: return(s);
1247: }
1248: }
1249: asgwrite(p);
1250: longjmp(back, 1);
1251: }
1252: else if((flag & USED) && !((flag & CC) && (s.flag & CC))) {
1253: /* presumably USED as in *p++=*q++ */
1254: totemp(p, RIGHT);
1255: longjmp(back, 1);
1256: }
1257: }
1258: if(dest.ans) {
1259: x = s;
1260: goto movexdest;
1261: }
1262: else if(M32 && (flag & TOSTACK)) {
1263: pr("#\tpushw\t%s\n", str(s));
1264: return(s);
1265: }
1266: else if(flag & ASADDR) {
1267: i = (s.flag & (ISREG|CANINDIR|SCRATCH));
1268: j = s.regmask;
1269: buf = str(s);
1270: goto convbuf;
1271: }
1272: return(s);
1273: }
1274: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.