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