1 /* $Id: local2.c,v 1.1 2014/09/16 10:47:35 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 # include "pass2.h"
30 # include <ctype.h>
31 # include <string.h>
32
33 #define EXPREFIX "_"
34
35
36 static int stkpos;
37
38 void
deflab(int label)39 deflab(int label)
40 {
41 printf(LABFMT ":\n", label);
42 }
43
44 static int regoff[7];
45 static TWORD ftype;
46
47 /*
48 * Print out the prolog assembler.
49 * addto and regoff are already calculated.
50 */
51 static void
prtprolog(struct interpass_prolog * ipp,int addto)52 prtprolog(struct interpass_prolog *ipp, int addto)
53 {
54 int i;
55
56 #if 1
57 /* FIXME: can't use enter/leave if generating i8086 */
58 if (addto == 0 || addto > 65535 || 1) {
59 printf(" push bp\n\tmov sp,bp\n");
60 if (addto)
61 printf(" sub sp,%d\n", addto);
62 } else
63 printf(" enter %d,0\n", addto);
64 #endif
65 for (i = 0; i < MAXREGS; i++)
66 if (TESTBIT(ipp->ipp_regs, i))
67 printf(" mov -%d[%s],%s\n",
68 regoff[i], rnames[FPREG], rnames[i]);
69 }
70
71 /*
72 * calculate stack size and offsets
73 */
74 static int
offcalc(struct interpass_prolog * ipp)75 offcalc(struct interpass_prolog *ipp)
76 {
77 int i, addto;
78
79 addto = p2maxautooff;
80 if (addto >= AUTOINIT/SZCHAR)
81 addto -= AUTOINIT/SZCHAR;
82 for (i = 0; i < MAXREGS; i++)
83 if (TESTBIT(ipp->ipp_regs, i)) {
84 addto += SZINT/SZCHAR;
85 regoff[i] = addto;
86 }
87 return addto;
88 }
89
90 void
prologue(struct interpass_prolog * ipp)91 prologue(struct interpass_prolog *ipp)
92 {
93 int addto;
94
95 ftype = ipp->ipp_type;
96
97 #ifdef LANG_F77
98 if (ipp->ipp_vis)
99 printf(" .globl %s\n", ipp->ipp_name);
100 printf(" .align 4\n");
101 printf("%s:\n", ipp->ipp_name);
102 #endif
103 /*
104 * We here know what register to save and how much to
105 * add to the stack.
106 */
107 addto = offcalc(ipp);
108 prtprolog(ipp, addto);
109 }
110
111 void
eoftn(struct interpass_prolog * ipp)112 eoftn(struct interpass_prolog *ipp)
113 {
114 int i;
115
116 if (ipp->ipp_ip.ip_lbl == 0)
117 return; /* no code needs to be generated */
118
119 /* return from function code */
120 for (i = 0; i < MAXREGS; i++)
121 if (TESTBIT(ipp->ipp_regs, i))
122 printf(" mov %s,-%d[%s]\n",
123 rnames[i],regoff[i], rnames[FPREG]);
124
125 /* struct return needs special treatment */
126 if (ftype == STRTY || ftype == UNIONTY) {
127 printf(" mov ax, 8[bp]\n");
128 printf(" leave\n");
129 /* FIXME: ret n is not in 8086 */
130 printf(" ret %d\n", 4 + ipp->ipp_argstacksize);
131 } else {
132 printf(" mov sp, bp\n");
133 printf(" pop bp\n");
134 if (ipp->ipp_argstacksize)
135 /* CHECK ME */
136 printf(" add sp, %d\n", ipp->ipp_argstacksize);
137 printf(" ret\n");
138 }
139 }
140
141 /*
142 * add/sub/...
143 *
144 * Param given:
145 */
146 void
hopcode(int f,int o)147 hopcode(int f, int o)
148 {
149 char *str;
150
151 switch (o) {
152 case PLUS:
153 str = "add";
154 break;
155 case MINUS:
156 str = "sub";
157 break;
158 case AND:
159 str = "and";
160 break;
161 case OR:
162 str = "or";
163 break;
164 case ER:
165 str = "xor";
166 break;
167 default:
168 comperr("hopcode2: %d", o);
169 str = 0; /* XXX gcc */
170 }
171 printf("%s%c", str, f);
172 }
173
174 /*
175 * Return type size in bytes. Used by R2REGS, arg 2 to offset().
176 */
177 int
tlen(NODE * p)178 tlen(NODE *p)
179 {
180 switch(p->n_type) {
181 case CHAR:
182 case UCHAR:
183 return(1);
184
185 case SHORT:
186 case USHORT:
187 case INT:
188 case UNSIGNED:
189 return(SZINT/SZCHAR);
190
191 case DOUBLE:
192 return(SZDOUBLE/SZCHAR);
193
194 case LONG:
195 case ULONG:
196 return(SZLONG/SZCHAR);
197
198 case LONGLONG:
199 case ULONGLONG:
200 return SZLONGLONG/SZCHAR;
201
202 default:
203 if (!ISPTR(p->n_type))
204 comperr("tlen type %d not pointer");
205 return SZPOINT(p->n_type)/SZCHAR;
206 }
207 }
208
209 /*
210 * Emit code to compare two long numbers.
211 */
212 static void
twollcomp(NODE * p)213 twollcomp(NODE *p)
214 {
215 int u;
216 int s = getlab2();
217 int e = p->n_label;
218 int cb1, cb2;
219
220 u = p->n_op;
221 switch (p->n_op) {
222 case NE:
223 cb1 = 0;
224 cb2 = NE;
225 break;
226 case EQ:
227 cb1 = NE;
228 cb2 = 0;
229 break;
230 case LE:
231 case LT:
232 u += (ULE-LE);
233 /* FALLTHROUGH */
234 case ULE:
235 case ULT:
236 cb1 = GT;
237 cb2 = LT;
238 break;
239 case GE:
240 case GT:
241 u += (ULE-LE);
242 /* FALLTHROUGH */
243 case UGE:
244 case UGT:
245 cb1 = LT;
246 cb2 = GT;
247 break;
248
249 default:
250 cb1 = cb2 = 0; /* XXX gcc */
251 }
252 if (p->n_op >= ULE)
253 cb1 += 4, cb2 += 4;
254 expand(p, 0, " cmp UL,UR\n");
255 if (cb1) cbgen(cb1, s);
256 if (cb2) cbgen(cb2, e);
257 expand(p, 0, " cmp AL,AR\n");
258 cbgen(u, e);
259 deflab(s);
260 }
261
262 int
fldexpand(NODE * p,int cookie,char ** cp)263 fldexpand(NODE *p, int cookie, char **cp)
264 {
265 comperr("fldexpand");
266 return 0;
267 }
268
269 /*
270 * Push a structure on stack as argument.
271 * the scratch registers are already free here
272 */
273 static void
starg(NODE * p)274 starg(NODE *p)
275 {
276 NODE *q = p->n_left;
277 int s = (p->n_stsize + 1) & ~1;
278
279 if (s == 2)
280 printf(" dec sp\n dec sp\n");
281 else
282 printf(" sub sp,%d\n", s);
283 p->n_left = mklnode(OREG, 0, SP, INT);
284 zzzcode(p, 'Q');
285 tfree(p->n_left);
286 p->n_left = q;
287 }
288
289 /*
290 * Compare two floating point numbers.
291 */
292 static void
fcomp(NODE * p)293 fcomp(NODE *p)
294 {
295 static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
296
297 if ((p->n_su & DORIGHT) == 0)
298 expand(p, 0, "\tfxch\n");
299 expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */
300 expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */
301
302 if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
303 expand(p, 0, "\tjp LC\n");
304 else if (p->n_op == EQ)
305 printf("\tjp 1f\n");
306 printf(" %s ", fpcb[p->n_op - EQ]);
307 expand(p, 0, "LC\n");
308 if (p->n_op == EQ)
309 printf("1:\n");
310 }
311
312 /*
313 * Convert an unsigned long long to floating point number.
314 */
315 static void
ulltofp(NODE * p)316 ulltofp(NODE *p)
317 {
318 int jmplab;
319
320 jmplab = getlab2();
321 expand(p, 0, " push UL\n push AL\n");
322 expand(p, 0, " fildq (%esp)\n");
323 expand(p, 0, " add sp, 8\n");
324 expand(p, 0, " cmp UL, 0\n");
325 printf(" jge " LABFMT "\n", jmplab);
326
327 //#if defined(ELFABI)
328 //FIXME printf(" fldt " LABFMT "%s\n", loadlab, kflag ? "@GOTOFF" : "");
329 //#elif defined(MACHOABI)
330 // printf("\tpushl 0x5f800000\n");
331 // printf("\tfadds (%%sp)\n");
332 // printf("\tadd $4,%%sp\n");
333 //#else
334 //#error incomplete implementation
335 //#endif
336
337 printf(" faddp %%st,%%st(1)\n");
338 printf(LABFMT ":\n", jmplab);
339 }
340
341 static int
argsiz(NODE * p)342 argsiz(NODE *p)
343 {
344 TWORD t = p->n_type;
345 if (t < LONG)
346 return 2;
347 if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG)
348 return 4;
349 if (t == FLOAT)
350 return 4;
351 if (t > BTMASK)
352 return 2;
353 if (t == DOUBLE)
354 return 8;
355 if (t == LDOUBLE)
356 return 12;
357 if (t == STRTY || t == UNIONTY)
358 return (p->n_stsize+1) & ~1;
359 comperr("argsiz");
360 return 0;
361 }
362
363 static void
fcast(NODE * p)364 fcast(NODE *p)
365 {
366 TWORD t = p->n_type;
367 int sz, c;
368
369 if (t >= p->n_left->n_type)
370 return; /* cast to more precision */
371 if (t == FLOAT)
372 sz = 4, c = 's';
373 else
374 sz = 8, c = 'l';
375
376 printf(" sub sp, %d\n", sz);
377 printf(" fstp%c (%%sp)\n", c);
378 printf(" fld%c (%%sp)\n", c);
379 printf(" add sp, %d\n", sz);
380 }
381
382 static void
llshft(NODE * p)383 llshft(NODE *p)
384 {
385 /* FIXME: we have sal/shl/sar/shr but we are limited to
386 shift right or left 1
387 shift right or left by CL */
388 char *d[3];
389
390 if (p->n_op == LS) {
391 d[0] = "l", d[1] = "ax", d[2] = "dx";
392 } else
393 d[0] = "r", d[1] = "dx", d[2] = "ax";
394
395 printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
396 printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
397 (p->n_left->n_type == ULONG || p->n_left->n_type == ULONGLONG) ?
398 "h" : "a", d[0], d[1]);
399 printf("\ttestb $16,%%cl\n");
400 printf("\tje 1f\n");
401 printf("\tmov %s,%s\n", d[1], d[2]);
402 if (p->n_op == RS && (p->n_left->n_type == LONGLONG|| p->n_left->n_type == LONG))
403 printf("\tsarl $31,%%edx\n");
404 else
405 printf("\txor %s,%s\n",d[1],d[1]);
406 printf("1:\n");
407 }
408
409 void
zzzcode(NODE * p,int c)410 zzzcode(NODE *p, int c)
411 {
412 NODE *l;
413 int pr, lr;
414 char *ch;
415
416 switch (c) {
417 case 'A': /* swap st0 and st1 if right is evaluated second */
418 if ((p->n_su & DORIGHT) == 0) {
419 if (logop(p->n_op))
420 printf(" fxch\n");
421 else
422 printf("r");
423 }
424 break;
425
426 case 'C': /* remove from stack after subroutine call */
427 #ifdef notdef
428 if (p->n_left->n_flags & FSTDCALL)
429 break;
430 #endif
431 pr = p->n_qual;
432 if (p->n_flags & FFPPOP)
433 printf(" fstp st(0)\n");
434 if (p->n_op == UCALL)
435 return; /* XXX remove ZC from UCALL */
436 if (pr) {
437 if (pr == 2)
438 printf(" inc sp\n inc sp\n");
439 else
440 printf(" add sp,%d\n", pr);
441 }
442 break;
443
444 case 'D': /* Long comparision */
445 twollcomp(p);
446 break;
447
448 case 'F': /* Structure argument */
449 if (p->n_stalign != 0) /* already on stack */
450 starg(p);
451 break;
452
453 case 'G': /* Floating point compare */
454 fcomp(p);
455 break;
456
457 case 'H': /* assign of long between regs */
458 rmove(DECRA(p->n_right->n_reg, 0),
459 DECRA(p->n_left->n_reg, 0), LONGLONG);
460 break;
461
462 case 'I': /* float casts */
463 fcast(p);
464 break;
465
466 case 'J': /* convert unsigned long long to floating point */
467 ulltofp(p);
468 break;
469
470 case 'K': /* Load long reg into another reg */
471 rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
472 break;
473
474 case 'M': /* Output sconv move, if needed */
475 l = getlr(p, 'L');
476 /* XXX fixneed: regnum */
477 pr = DECRA(p->n_reg, 0);
478 lr = DECRA(l->n_reg, 0);
479 if ((pr == AL && lr == AX) || (pr == BL && lr == BX) ||
480 (pr == CL && lr == CX) || (pr == DL && lr == DX))
481 ;
482 else
483 printf(" mov %s, %cL\n",
484 rnames[pr], rnames[lr][1]);
485 l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
486 break;
487
488 case 'N': /* output extended reg name */
489 printf("%s", rnames[getlr(p, '1')->n_rval]);
490 break;
491
492 case 'O': /* print out emulated ops */
493 pr = 16;
494 if (p->n_op == RS || p->n_op == LS) {
495 llshft(p);
496 break;
497 } else if (p->n_op == MUL) {
498 /* FIXME */
499 printf("\tmul dx, cx\n");
500 printf("\tmul si, ax\n");
501 printf("\tadd si, dx\n");
502 printf("\tmul cx\n");
503 printf("\tadd dx, si\n");
504 break;
505 }
506 expand(p, INCREG, "\tpush UR\n\tpush AR\n");
507 expand(p, INCREG, "\tpush UL\n\tpush AL\n");
508 if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG))
509 ch = "udiv";
510 else if (p->n_op == DIV) ch = "div";
511 else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG))
512 ch = "umod";
513 else if (p->n_op == MOD) ch = "mod";
514 else ch = 0, comperr("ZO");
515 printf("\tcall " EXPREFIX "__%sdi3\n\tadd %s,%d\n",
516 ch, rnames[SP], pr);
517 break;
518
519 case 'Q': /* emit struct assign */
520 /*
521 * Put out some combination of movs{b,w}
522 * si/di/cx are available.
523 * FIXME: review es: and direction flag implications
524 */
525 expand(p, INAREG, " lea al,di\n");
526 if (p->n_stsize < 32) {
527 int i = p->n_stsize >> 1;
528 while (i) {
529 expand(p, INAREG, " movsw\n");
530 i--;
531 }
532 } else {
533 printf("\tmov cx, %d\n", p->n_stsize >> 1);
534 printf(" rep movsw\n");
535 }
536 if (p->n_stsize & 2)
537 printf(" movsw\n");
538 if (p->n_stsize & 1)
539 printf(" movsb\n");
540 break;
541
542 case 'S': /* emit eventual move after cast from long */
543 pr = DECRA(p->n_reg, 0);
544 lr = p->n_left->n_rval;
545 switch (p->n_type) {
546 case CHAR:
547 case UCHAR:
548 if (rnames[pr][1] == 'L' && rnames[lr][1] == 'X' &&
549 rnames[pr][0] == rnames[lr][0])
550 break;
551 if (rnames[lr][1] == 'X') {
552 printf("\tmov %s, %cL\n",
553 rnames[pr], rnames[lr][0]);
554 break;
555 }
556 /* Must go via stack */
557 expand(p, INAREG, "\tmov A2,AL\n");
558 expand(p, INBREG, "\tmov A1,A2\n");
559 #ifdef notdef
560 /* cannot use freetemp() in instruction emission */
561 s = freetemp(1);
562 printf("\tmov %ci,%d(bp)\n", rnames[lr][0], s);
563 printf("\tmov %s, %d(bp)\n", rnames[pr], s);
564 #endif
565 break;
566
567 case INT:
568 case UNSIGNED:
569 if (rnames[lr][0] == rnames[pr][1] &&
570 rnames[lr][1] == rnames[pr][2])
571 break;
572 printf("\tmov %s, %c%c\n",
573 rnames[pr], rnames[lr][0], rnames[lr][1]);
574 break;
575
576 default:
577 if (rnames[lr][0] == rnames[pr][1] &&
578 rnames[lr][1] == rnames[pr][2])
579 break;
580 comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
581 break;
582 }
583 break;
584 case 'T':
585 /* Conversions from unsigned char to int/ptr */
586 /* Cannot be in DI or SI */
587 l = getlr(p, 'L');
588 lr = regno(l);
589 pr = regno(getlr(p, '1'));
590 if (l->n_op != REG) { /* NAME or OREG */
591 /* Need to force a movb into the low half, using
592 a movw might fail in protected mode or with
593 mmio spaces */
594 printf(" movb %cl, ", rnames[pr][0]);
595 expand(p, INAREG, "AL\n");
596 } else {
597 if ((lr == AL && pr == AX) ||
598 (lr == BL && pr == BX) ||
599 (lr == CL && pr == CX) ||
600 (lr == DL && pr == DX))
601 ;
602 else
603 printf(" movb %cl,%cl\n",
604 rnames[pr][0],rnames[lr][0]);
605 }
606 printf(" xorb %ch,%ch\n",
607 rnames[pr][0], rnames[pr][0]);
608 break;
609 break;
610 default:
611 comperr("zzzcode %c", c);
612 }
613 }
614
615 int canaddr(NODE *);
616 int
canaddr(NODE * p)617 canaddr(NODE *p)
618 {
619 int o = p->n_op;
620
621 if (o==NAME || o==REG || o==ICON || o==OREG ||
622 (o==UMUL && shumul(p->n_left, SOREG)))
623 return(1);
624 return(0);
625 }
626
627 /*
628 * Does the bitfield shape match?
629 */
630 int
flshape(NODE * p)631 flshape(NODE *p)
632 {
633 comperr("flshape");
634 return 0;
635 }
636
637 /* INTEMP shapes must not contain any temporary registers */
638 /* XXX should this go away now? */
639 int
shtemp(NODE * p)640 shtemp(NODE *p)
641 {
642 return 0;
643 #if 0
644 int r;
645
646 if (p->n_op == STARG )
647 p = p->n_left;
648
649 switch (p->n_op) {
650 case REG:
651 return (!istreg(p->n_rval));
652
653 case OREG:
654 r = p->n_rval;
655 if (R2TEST(r)) {
656 if (istreg(R2UPK1(r)))
657 return(0);
658 r = R2UPK2(r);
659 }
660 return (!istreg(r));
661
662 case UMUL:
663 p = p->n_left;
664 return (p->n_op != UMUL && shtemp(p));
665 }
666
667 if (optype(p->n_op) != LTYPE)
668 return(0);
669 return(1);
670 #endif
671 }
672
673 void
adrcon(CONSZ val)674 adrcon(CONSZ val)
675 {
676 printf("$" CONFMT, val);
677 }
678
679 void
conput(FILE * fp,NODE * p)680 conput(FILE *fp, NODE *p)
681 {
682 int val = (int)p->n_lval;
683
684 switch (p->n_op) {
685 case ICON:
686 if (p->n_name[0] != '\0') {
687 fprintf(fp, "%s", p->n_name);
688 if (val)
689 fprintf(fp, "+%d", val);
690 } else
691 fprintf(fp, "%d", val);
692 return;
693
694 default:
695 comperr("illegal conput, p %p", p);
696 }
697 }
698
699 /*ARGSUSED*/
700 void
insput(NODE * p)701 insput(NODE *p)
702 {
703 comperr("insput");
704 }
705
706 /*
707 * Write out the upper address, like the upper register of a 2-register
708 * reference, or the next memory location.
709 */
710 void
upput(NODE * p,int size)711 upput(NODE *p, int size)
712 {
713
714 size /= SZCHAR;
715 switch (p->n_op) {
716 case REG:
717 printf("%s", &rnames[p->n_rval][2]);
718 break;
719
720 case NAME:
721 case OREG:
722 p->n_lval += size;
723 adrput(stdout, p);
724 p->n_lval -= size;
725 break;
726 case ICON:
727 printf(CONFMT, p->n_lval >> 16);
728 break;
729 default:
730 comperr("upput bad op %d size %d", p->n_op, size);
731 }
732 }
733
734 void
adrput(FILE * io,NODE * p)735 adrput(FILE *io, NODE *p)
736 {
737 int r;
738 /* output an address, with offsets, from p */
739
740 switch (p->n_op) {
741
742 case NAME:
743 if (p->n_name[0] != '\0') {
744 printf("[");
745 fputs(p->n_name, io);
746 if (p->n_lval != 0)
747 fprintf(io, "+" CONFMT, p->n_lval);
748 printf("]");
749 } else
750 fprintf(io, CONFMT, p->n_lval);
751 return;
752
753 case OREG:
754 r = p->n_rval;
755 if (p->n_name[0])
756 printf("%s%s", p->n_name, p->n_lval ? "+" : "");
757 if (p->n_lval)
758 fprintf(io, "%d", (int)p->n_lval);
759 printf("[");
760 if (R2TEST(r)) {
761 fprintf(io, "%s,%s,4", rnames[R2UPK1(r)],
762 rnames[R2UPK2(r)]);
763 } else
764 fprintf(io, "%s", rnames[p->n_rval]);
765 printf("]");
766 return;
767 case ICON:
768 #ifdef PCC_DEBUG
769 /* Sanitycheck for PIC, to catch adressable constants */
770 if (kflag && p->n_name[0] && 0) {
771 static int foo;
772
773 if (foo++ == 0) {
774 printf("\nfailing...\n");
775 fwalk(p, e2print, 0);
776 comperr("pass2 conput");
777 }
778 }
779 #endif
780 /* addressable value of the constant */
781 conput(io, p);
782 return;
783
784 case REG:
785 switch (p->n_type) {
786 case LONGLONG:
787 case ULONGLONG:
788 case LONG:
789 case ULONG:
790 fprintf(io, "%c%c", rnames[p->n_rval][0],
791 rnames[p->n_rval][1]);
792 break;
793 default:
794 fprintf(io, "%s", rnames[p->n_rval]);
795 }
796 return;
797
798 default:
799 comperr("illegal address, op %d, node %p", p->n_op, p);
800 return;
801
802 }
803 }
804
805 static char *
806 ccbranches[] = {
807 "je", /* jumpe */
808 "jne", /* jumpn */
809 "jle", /* jumple */
810 "jl", /* jumpl */
811 "jge", /* jumpge */
812 "jg", /* jumpg */
813 "jbe", /* jumple (jlequ) */
814 "jb", /* jumpl (jlssu) */
815 "jae", /* jumpge (jgequ) */
816 "ja", /* jumpg (jgtru) */
817 };
818
819
820 /* printf conditional and unconditional branches */
821 void
cbgen(int o,int lab)822 cbgen(int o, int lab)
823 {
824 if (o < EQ || o > UGT)
825 comperr("bad conditional branch: %s", opst[o]);
826 printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
827 }
828
829 static void
fixcalls(NODE * p,void * arg)830 fixcalls(NODE *p, void *arg)
831 {
832 /* Prepare for struct return by allocating bounce space on stack */
833 switch (p->n_op) {
834 case STCALL:
835 case USTCALL:
836 if (p->n_stsize+p2autooff > stkpos)
837 stkpos = p->n_stsize+p2autooff;
838 break;
839 case LS:
840 case RS:
841 if (p->n_type != LONGLONG && p->n_type != ULONGLONG
842 && p->n_type != LONG && p->n_type != ULONG)
843 break;
844 if (p->n_right->n_op == ICON) /* constants must be char */
845 p->n_right->n_type = CHAR;
846 break;
847 }
848 }
849
850 /*
851 * Must store floats in memory if there are two function calls involved.
852 */
853 static int
storefloat(struct interpass * ip,NODE * p)854 storefloat(struct interpass *ip, NODE *p)
855 {
856 int l, r;
857
858 switch (optype(p->n_op)) {
859 case BITYPE:
860 l = storefloat(ip, p->n_left);
861 r = storefloat(ip, p->n_right);
862 if (p->n_op == CM)
863 return 0; /* arguments, don't care */
864 if (callop(p->n_op))
865 return 1; /* found one */
866 #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
867 (p)->n_type == LDOUBLE)
868 if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
869 /* must store one. store left */
870 struct interpass *nip;
871 TWORD t = p->n_left->n_type;
872 NODE *ll;
873 int off;
874
875 off = freetemp(szty(t));
876 ll = mklnode(OREG, off, FPREG, t);
877 nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
878 p->n_left = mklnode(OREG, off, FPREG, t);
879 DLIST_INSERT_BEFORE(ip, nip, qelem);
880 }
881 return l|r;
882
883 case UTYPE:
884 l = storefloat(ip, p->n_left);
885 if (callop(p->n_op))
886 l = 1;
887 return l;
888 default:
889 return 0;
890 }
891 }
892
893 static void
outfargs(struct interpass * ip,NODE ** ary,int num,int * cwp,int c)894 outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
895 {
896 struct interpass *ip2;
897 NODE *q, *r;
898 int i;
899
900 for (i = 0; i < num; i++)
901 if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
902 break;
903 if (i == num)
904 return;
905 q = ary[i]->n_left;
906 r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
907 ary[i]->n_left = tcopy(r);
908 ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
909 DLIST_INSERT_AFTER(ip, ip2, qelem);
910 }
911
912 static void
infargs(struct interpass * ip,NODE ** ary,int num,int * cwp,int c)913 infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
914 {
915 struct interpass *ip2;
916 NODE *q, *r;
917 int i;
918
919 for (i = 0; i < num; i++)
920 if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
921 break;
922 if (i == num)
923 return;
924 q = ary[i]->n_left;
925 q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
926 r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
927 if ((cwp[i] & XASMINOUT) == 0)
928 ary[i]->n_left = tcopy(r);
929 ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
930 DLIST_INSERT_BEFORE(ip, ip2, qelem);
931 }
932
933 /*
934 * Extract float args to XASM and ensure that they are put on the stack
935 * in correct order.
936 * This should be done sow other way.
937 */
938 static void
fixxfloat(struct interpass * ip,NODE * p)939 fixxfloat(struct interpass *ip, NODE *p)
940 {
941 NODE *w, **ary;
942 int nn, i, c, *cwp;
943
944 nn = 1;
945 w = p->n_left;
946 if (w->n_op == ICON && w->n_type == STRTY)
947 return;
948 /* index all xasm args first */
949 for (; w->n_op == CM; w = w->n_left)
950 nn++;
951 ary = tmpcalloc(nn * sizeof(NODE *));
952 cwp = tmpcalloc(nn * sizeof(int));
953 for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
954 ary[i] = w->n_right;
955 cwp[i] = xasmcode(ary[i]->n_name);
956 i++;
957 }
958 ary[i] = w;
959 cwp[i] = xasmcode(ary[i]->n_name);
960 for (i = 0; i < nn; i++)
961 if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
962 break;
963 if (i == nn)
964 return;
965
966 for (i = 0; i < nn; i++) {
967 c = XASMVAL(cwp[i]);
968 if (c >= '0' && c <= '9')
969 cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
970 }
971 infargs(ip, ary, nn, cwp, 'u');
972 infargs(ip, ary, nn, cwp, 't');
973 outfargs(ip, ary, nn, cwp, 't');
974 outfargs(ip, ary, nn, cwp, 'u');
975 }
976
977 static NODE *
lptr(NODE * p)978 lptr(NODE *p)
979 {
980 if (p->n_op == ASSIGN && p->n_right->n_op == REG &&
981 regno(p->n_right) == BP)
982 return p->n_right;
983 if (p->n_op == FUNARG && p->n_left->n_op == REG &&
984 regno(p->n_left) == BP)
985 return p->n_left;
986 return NIL;
987 }
988
989 /*
990 * Find arg reg that should be struct reference instead.
991 */
992 static void
updatereg(NODE * p,void * arg)993 updatereg(NODE *p, void *arg)
994 {
995 NODE *q;
996
997 if (p->n_op != STCALL)
998 return;
999 if (p->n_right->n_op != CM)
1000 p = p->n_right;
1001 else for (p = p->n_right;
1002 p->n_op == CM && p->n_left->n_op == CM; p = p->n_left)
1003 ;
1004 if (p->n_op == CM) {
1005 if ((q = lptr(p->n_left)))
1006 ;
1007 else
1008 q = lptr(p->n_right);
1009 } else
1010 q = lptr(p);
1011 if (q == NIL)
1012 comperr("bad STCALL hidden reg");
1013
1014 /* q is now the hidden arg */
1015 q->n_op = MINUS;
1016 q->n_type = INCREF(CHAR);
1017 q->n_left = mklnode(REG, 0, BP, INCREF(CHAR));
1018 q->n_right = mklnode(ICON, stkpos, 0, INT);
1019 }
1020
1021 void
myreader(struct interpass * ipole)1022 myreader(struct interpass *ipole)
1023 {
1024 struct interpass *ip;
1025
1026 stkpos = p2autooff;
1027 DLIST_FOREACH(ip, ipole, qelem) {
1028 if (ip->type != IP_NODE)
1029 continue;
1030 walkf(ip->ip_node, fixcalls, 0);
1031 storefloat(ip, ip->ip_node);
1032 if (ip->ip_node->n_op == XASM)
1033 fixxfloat(ip, ip->ip_node);
1034 }
1035 if (stkpos != p2autooff) {
1036 DLIST_FOREACH(ip, ipole, qelem) {
1037 if (ip->type != IP_NODE)
1038 continue;
1039 walkf(ip->ip_node, updatereg, 0);
1040 }
1041 }
1042 if (stkpos > p2autooff)
1043 p2autooff = stkpos;
1044 if (stkpos > p2maxautooff)
1045 p2maxautooff = stkpos;
1046 if (x2debug)
1047 printip(ipole);
1048 }
1049
1050 /*
1051 * Remove some PCONVs after OREGs are created.
1052 */
1053 static void
pconv2(NODE * p,void * arg)1054 pconv2(NODE *p, void *arg)
1055 {
1056 NODE *q;
1057 if (p->n_op == PLUS) {
1058 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
1059 if (p->n_right->n_op != ICON)
1060 return;
1061 if (p->n_left->n_op != PCONV)
1062 return;
1063 if (p->n_left->n_left->n_op != OREG)
1064 return;
1065 q = p->n_left->n_left;
1066 nfree(p->n_left);
1067 p->n_left = q;
1068 /*
1069 * This will be converted to another OREG later.
1070 */
1071 }
1072 }
1073 }
1074
1075 void
mycanon(NODE * p)1076 mycanon(NODE *p)
1077 {
1078 walkf(p, pconv2, 0);
1079 }
1080
1081 void
myoptim(struct interpass * ip)1082 myoptim(struct interpass *ip)
1083 {
1084 }
1085
1086 static char rl[] =
1087 { AX, AX, AX, AX, AX, DX, DX, DX, DX, CX, CX, CX, BX, BX, SI };
1088 static char rh[] =
1089 { DX, CX, BX, SI, DI, CX, BX, SI, DI, BX, SI, DI, SI, DI, DI };
1090
1091 void
rmove(int s,int d,TWORD t)1092 rmove(int s, int d, TWORD t)
1093 {
1094 int sl, sh, dl, dh;
1095
1096 switch (t) {
1097 case LONGLONG:
1098 case ULONGLONG:
1099 case LONG:
1100 case ULONG: /* ?? FIXME check */
1101 #if 1
1102 sl = rl[s-AXDX];
1103 sh = rh[s-AXDX];
1104 dl = rl[d-AXDX];
1105 dh = rh[d-AXDX];
1106
1107 /* sanity checks, remove when satisfied */
1108 if (memcmp(rnames[s], rnames[sl], 2) != 0 ||
1109 memcmp(rnames[s]+2, rnames[sh], 2) != 0)
1110 comperr("rmove source error");
1111 if (memcmp(rnames[d], rnames[dl], 2) != 0 ||
1112 memcmp(rnames[d]+2, rnames[dh], 2) != 0)
1113 comperr("rmove dest error");
1114 #define SW(x,y) { int i = x; x = y; y = i; }
1115 if (sh == dl) {
1116 /* Swap if overwriting */
1117 SW(sl, sh);
1118 SW(dl, dh);
1119 }
1120 if (sl != dl)
1121 printf(" mov %s,%s\n", rnames[dl], rnames[sl]);
1122 if (sh != dh)
1123 printf(" mov %s,%s\n", rnames[dh], rnames[sh]);
1124 #else
1125 if (memcmp(rnames[s], rnames[d], 2) != 0)
1126 printf(" mov %c%c,%c%c\n",
1127 rnames[d][0],rnames[d][1],
1128 rnames[s][0],rnames[s][1]);
1129 if (memcmp(&rnames[s][2], &rnames[d][2], 2) != 0)
1130 printf(" mov %c%c,%c%c\n",
1131 rnames[d][2],rnames[d][3]
1132 rnames[s][2],rnames[s][3]);
1133 #endif
1134 break;
1135 case CHAR:
1136 case UCHAR:
1137 printf(" movb %s,%s\n", rnames[d], rnames[s]);
1138 break;
1139 case FLOAT:
1140 case DOUBLE:
1141 case LDOUBLE:
1142 #ifdef notdef
1143 /* a=b()*c(); will generate this */
1144 comperr("bad float rmove: %d %d", s, d);
1145 #endif
1146 break;
1147 default:
1148 printf(" mov %s,%s\n", rnames[d], rnames[s]);
1149 }
1150 }
1151
1152 /*
1153 * For class c, find worst-case displacement of the number of
1154 * registers in the array r[] indexed by class.
1155 */
1156 int
COLORMAP(int c,int * r)1157 COLORMAP(int c, int *r)
1158 {
1159 int num;
1160
1161 switch (c) {
1162 case CLASSA:
1163 num = r[CLASSB] > 4 ? 4 : r[CLASSB];
1164 num += 2*r[CLASSC];
1165 num += r[CLASSA];
1166 return num < 6;
1167 case CLASSB:
1168 num = r[CLASSA];
1169 num += 2*r[CLASSC];
1170 num += r[CLASSB];
1171 return num < 4;
1172 case CLASSC:
1173 num = r[CLASSA];
1174 num += r[CLASSB] > 4 ? 4 : r[CLASSB];
1175 num += 2*r[CLASSC];
1176 return num < 5;
1177 case CLASSD:
1178 return r[CLASSD] < DREGCNT;
1179 }
1180 return 0; /* XXX gcc */
1181 }
1182
1183 char *rnames[] = {
1184 "ax", "dx", "cx", "bx", "si", "di", "bp", "sp",
1185 "al", "ah", "dl", "dh", "cl", "ch", "bl", "bh",
1186 "axdx", "axcx", "axbx", "axsi", "axdi", "dxcx",
1187 "dxbx", "dxsi", "dxdi", "cxbx", "cxsi", "cxdi",
1188 "bxsi", "bxdi", "sidi",
1189 "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7",
1190 };
1191
1192 /*
1193 * Return a class suitable for a specific type.
1194 */
1195 int
gclass(TWORD t)1196 gclass(TWORD t)
1197 {
1198 if (t == CHAR || t == UCHAR)
1199 return CLASSB;
1200 if (t == LONGLONG || t == ULONGLONG || t == LONG || t == ULONG)
1201 return CLASSC;
1202 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
1203 return CLASSD;
1204 return CLASSA;
1205 }
1206
1207 /*
1208 * Calculate argument sizes.
1209 */
1210 void
lastcall(NODE * p)1211 lastcall(NODE *p)
1212 {
1213 NODE *op = p;
1214 int size = 0;
1215
1216 p->n_qual = 0;
1217 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1218 return;
1219 for (p = p->n_right; p->n_op == CM; p = p->n_left) {
1220 if (p->n_right->n_op != ASSIGN)
1221 size += argsiz(p->n_right);
1222 }
1223 if (p->n_op != ASSIGN)
1224 size += argsiz(p);
1225
1226 op->n_qual = size; /* XXX */
1227 }
1228
1229 /*
1230 * Special shapes.
1231 */
1232 int
special(NODE * p,int shape)1233 special(NODE *p, int shape)
1234 {
1235 int o = p->n_op;
1236
1237 switch (shape) {
1238 case SFUNCALL:
1239 if (o == STCALL || o == USTCALL)
1240 return SRREG;
1241 break;
1242 case SPCON:
1243 if (o != ICON || p->n_name[0] ||
1244 p->n_lval < 0 || p->n_lval > 0x7fffffff)
1245 break;
1246 return SRDIR;
1247 case SMIXOR:
1248 return tshape(p, SZERO);
1249 case SMILWXOR:
1250 if (o != ICON || p->n_name[0] ||
1251 p->n_lval == 0 || p->n_lval & 0xffffffff)
1252 break;
1253 return SRDIR;
1254 case SMIHWXOR:
1255 if (o != ICON || p->n_name[0] ||
1256 p->n_lval == 0 || (p->n_lval >> 32) != 0)
1257 break;
1258 return SRDIR;
1259 }
1260 return SRNOPE;
1261 }
1262
1263 /*
1264 * Target-dependent command-line options.
1265 */
1266 void
mflags(char * str)1267 mflags(char *str)
1268 {
1269 }
1270
1271 /*
1272 * Do something target-dependent for xasm arguments.
1273 */
1274 int
myxasm(struct interpass * ip,NODE * p)1275 myxasm(struct interpass *ip, NODE *p)
1276 {
1277 struct interpass *ip2;
1278 int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
1279 NODE *in = 0, *ut = 0;
1280 TWORD t;
1281 char *w;
1282 int reg;
1283 int c, cw;
1284 CONSZ v;
1285
1286 cw = xasmcode(p->n_name);
1287 if (cw & (XASMASG|XASMINOUT))
1288 ut = p->n_left;
1289 if ((cw & XASMASG) == 0)
1290 in = p->n_left;
1291
1292 c = XASMVAL(cw);
1293 switch (c) {
1294 case 'D': reg = DI; break;
1295 case 'S': reg = SI; break;
1296 case 'a': reg = AX; break;
1297 case 'b': reg = BX; break;
1298 case 'c': reg = CX; break;
1299 case 'd': reg = DX; break;
1300
1301 case 't':
1302 case 'u':
1303 p->n_name = tmpstrdup(p->n_name);
1304 w = strchr(p->n_name, XASMVAL(cw));
1305 *w = 'r'; /* now reg */
1306 return 1;
1307
1308 case 'A': reg = AXDX; break;
1309 case 'q': {
1310 /* Set edges in MYSETXARG */
1311 if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
1312 return 1;
1313 t = p->n_left->n_type;
1314 if (in && ut)
1315 in = tcopy(in);
1316 p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
1317 if (ut) {
1318 ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1319 DLIST_INSERT_AFTER(ip, ip2, qelem);
1320 }
1321 if (in) {
1322 ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1323 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1324 }
1325 return 1;
1326 }
1327
1328 case 'I':
1329 case 'J':
1330 case 'K':
1331 case 'L':
1332 case 'M':
1333 case 'N':
1334 if (p->n_left->n_op != ICON) {
1335 if ((c = XASMVAL1(cw)) != 0) {
1336 p->n_name++;
1337 return 0; /* Try again */
1338 }
1339 uerror("xasm arg not constant");
1340 }
1341 v = p->n_left->n_lval;
1342 if ((c == 'K' && v < -128) ||
1343 (c == 'L' && v != 0xff && v != 0xffff) ||
1344 (c != 'K' && v < 0) ||
1345 (v > Cmax[c-'I']))
1346 uerror("xasm val out of range");
1347 p->n_name = "i";
1348 return 1;
1349
1350 default:
1351 return 0;
1352 }
1353 /* If there are requested either memory or register, delete memory */
1354 w = p->n_name = tmpstrdup(p->n_name);
1355 if (*w == '=')
1356 w++;
1357 *w++ = 'r';
1358 *w = 0;
1359
1360 t = p->n_left->n_type;
1361 if (reg == AXDX) {
1362 p->n_label = CLASSC;
1363 } else {
1364 p->n_label = CLASSA;
1365 if (t == CHAR || t == UCHAR) {
1366 p->n_label = CLASSB;
1367 reg = reg * 2 + 8;
1368 }
1369 }
1370 if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
1371 p->n_label = CLASSD;
1372 reg += 037;
1373 }
1374
1375 if (in && ut)
1376 in = tcopy(in);
1377 p->n_left = mklnode(REG, 0, reg, t);
1378 if (ut) {
1379 ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1380 DLIST_INSERT_AFTER(ip, ip2, qelem);
1381 }
1382 if (in) {
1383 ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1384 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1385 }
1386 return 1;
1387 }
1388
1389 void
targarg(char * w,void * arg)1390 targarg(char *w, void *arg)
1391 {
1392 NODE **ary = arg;
1393 NODE *p, *q;
1394
1395 if (ary[(int)w[1]-'0'] == 0)
1396 p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
1397 else
1398 p = ary[(int)w[1]-'0']->n_left;
1399 if (optype(p->n_op) != LTYPE)
1400 comperr("bad xarg op %d", p->n_op);
1401 q = tcopy(p);
1402 if (q->n_op == REG) {
1403 if (*w == 'k') {
1404 q->n_type = INT;
1405 } else if (*w != 'w') {
1406 if (q->n_type > UCHAR) {
1407 regno(q) = regno(q)*2+8;
1408 if (*w == 'h')
1409 regno(q)++;
1410 }
1411 q->n_type = INT;
1412 } else
1413 q->n_type = SHORT;
1414 }
1415 adrput(stdout, q);
1416 tfree(q);
1417 }
1418
1419 /*
1420 * target-specific conversion of numeric arguments.
1421 */
1422 int
numconv(void * ip,void * p1,void * q1)1423 numconv(void *ip, void *p1, void *q1)
1424 {
1425 NODE *p = p1, *q = q1;
1426 int cw = xasmcode(q->n_name);
1427
1428 switch (XASMVAL(cw)) {
1429 case 'a':
1430 case 'b':
1431 case 'c':
1432 case 'd':
1433 p->n_name = tmpcalloc(2);
1434 p->n_name[0] = (char)XASMVAL(cw);
1435 return 1;
1436 default:
1437 return 0;
1438 }
1439 }
1440
1441 static struct {
1442 char *name; int num;
1443 } xcr[] = {
1444 { "ax", AX },
1445 { "bx", BX },
1446 { "cx", CX },
1447 { "dx", DX },
1448 { "si", SI },
1449 { "di", DI },
1450 { NULL, 0 },
1451 };
1452
1453 /*
1454 * Check for other names of the xasm constraints registers.
1455 */
1456
1457 /*
1458 * Check for other names of the xasm constraints registers.
1459 */
xasmconstregs(char * s)1460 int xasmconstregs(char *s)
1461 {
1462 int i;
1463
1464 if (strncmp(s, "st", 2) == 0) {
1465 int off =0;
1466 if (s[2] == '(' && s[4] == ')')
1467 off = s[3] - '0';
1468 return SIDI + 1 + off;
1469 }
1470
1471 for (i = 0; xcr[i].name; i++)
1472 if (strcmp(xcr[i].name, s) == 0)
1473 return xcr[i].num;
1474 return -1;
1475 }
1476
1477