* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / i386 / local2.c
blobaab7b9af4e686a4386c19e1d74c082b163e4e934
1 /* $Id: local2.c,v 1.154.2.2 2011/02/26 07:17:34 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
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
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.
29 # include "pass2.h"
30 # include <ctype.h>
31 # include <string.h>
33 #if defined(PECOFFABI) || defined(MACHOABI)
34 #define EXPREFIX "_"
35 #else
36 #define EXPREFIX ""
37 #endif
40 static int stkpos;
42 void
43 deflab(int label)
45 printf(LABFMT ":\n", label);
48 static int regoff[7];
49 static TWORD ftype;
52 * Print out the prolog assembler.
53 * addto and regoff are already calculated.
55 static void
56 prtprolog(struct interpass_prolog *ipp, int addto)
58 int i;
60 printf(" pushl %%ebp\n");
61 printf(" movl %%esp,%%ebp\n");
62 #if defined(MACHOABI)
63 printf(" subl $8,%%esp\n"); /* 16-byte stack alignment */
64 #endif
65 if (addto)
66 printf(" subl $%d,%%esp\n", addto);
67 for (i = 0; i < MAXREGS; i++)
68 if (TESTBIT(ipp->ipp_regs, i))
69 fprintf(stdout, " movl %s,-%d(%s)\n",
70 rnames[i], regoff[i], rnames[FPREG]);
74 * calculate stack size and offsets
76 static int
77 offcalc(struct interpass_prolog *ipp)
79 int i, addto;
81 addto = p2maxautooff;
82 if (addto >= AUTOINIT/SZCHAR)
83 addto -= AUTOINIT/SZCHAR;
84 for (i = 0; i < MAXREGS; i++)
85 if (TESTBIT(ipp->ipp_regs, i)) {
86 addto += SZINT/SZCHAR;
87 regoff[i] = addto;
89 return addto;
92 void
93 prologue(struct interpass_prolog *ipp)
95 int addto;
97 ftype = ipp->ipp_type;
99 #ifdef LANG_F77
100 if (ipp->ipp_vis)
101 printf(" .globl %s\n", ipp->ipp_name);
102 printf(" .align 4\n");
103 printf("%s:\n", ipp->ipp_name);
104 #endif
106 * We here know what register to save and how much to
107 * add to the stack.
109 addto = offcalc(ipp);
110 #if defined(MACHOABI)
111 addto = (addto + 15) & ~15; /* stack alignment */
112 #endif
113 prtprolog(ipp, addto);
116 void
117 eoftn(struct interpass_prolog *ipp)
119 int i;
121 if (ipp->ipp_ip.ip_lbl == 0)
122 return; /* no code needs to be generated */
124 /* return from function code */
125 for (i = 0; i < MAXREGS; i++)
126 if (TESTBIT(ipp->ipp_regs, i))
127 fprintf(stdout, " movl -%d(%s),%s\n",
128 regoff[i], rnames[FPREG], rnames[i]);
130 /* struct return needs special treatment */
131 if (ftype == STRTY || ftype == UNIONTY) {
132 printf(" movl 8(%%ebp),%%eax\n");
133 printf(" leave\n");
134 printf(" ret $%d\n", 4 + ipp->ipp_argstacksize);
135 } else {
136 printf(" leave\n");
137 if (ipp->ipp_argstacksize)
138 printf(" ret $%d\n", ipp->ipp_argstacksize);
139 else
140 printf(" ret\n");
143 #if defined(ELFABI)
144 printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name,
145 ipp->ipp_name);
146 #endif
150 * add/sub/...
152 * Param given:
154 void
155 hopcode(int f, int o)
157 char *str;
159 switch (o) {
160 case PLUS:
161 str = "add";
162 break;
163 case MINUS:
164 str = "sub";
165 break;
166 case AND:
167 str = "and";
168 break;
169 case OR:
170 str = "or";
171 break;
172 case ER:
173 str = "xor";
174 break;
175 default:
176 comperr("hopcode2: %d", o);
177 str = 0; /* XXX gcc */
179 printf("%s%c", str, f);
183 * Return type size in bytes. Used by R2REGS, arg 2 to offset().
186 tlen(p) NODE *p;
188 switch(p->n_type) {
189 case CHAR:
190 case UCHAR:
191 return(1);
193 case SHORT:
194 case USHORT:
195 return(SZSHORT/SZCHAR);
197 case DOUBLE:
198 return(SZDOUBLE/SZCHAR);
200 case INT:
201 case UNSIGNED:
202 case LONG:
203 case ULONG:
204 return(SZINT/SZCHAR);
206 case LONGLONG:
207 case ULONGLONG:
208 return SZLONGLONG/SZCHAR;
210 default:
211 if (!ISPTR(p->n_type))
212 comperr("tlen type %d not pointer");
213 return SZPOINT(p->n_type)/SZCHAR;
218 * Emit code to compare two longlong numbers.
220 static void
221 twollcomp(NODE *p)
223 int u;
224 int s = getlab2();
225 int e = p->n_label;
226 int cb1, cb2;
228 u = p->n_op;
229 switch (p->n_op) {
230 case NE:
231 cb1 = 0;
232 cb2 = NE;
233 break;
234 case EQ:
235 cb1 = NE;
236 cb2 = 0;
237 break;
238 case LE:
239 case LT:
240 u += (ULE-LE);
241 /* FALLTHROUGH */
242 case ULE:
243 case ULT:
244 cb1 = GT;
245 cb2 = LT;
246 break;
247 case GE:
248 case GT:
249 u += (ULE-LE);
250 /* FALLTHROUGH */
251 case UGE:
252 case UGT:
253 cb1 = LT;
254 cb2 = GT;
255 break;
257 default:
258 cb1 = cb2 = 0; /* XXX gcc */
260 if (p->n_op >= ULE)
261 cb1 += 4, cb2 += 4;
262 expand(p, 0, " cmpl UR,UL\n");
263 if (cb1) cbgen(cb1, s);
264 if (cb2) cbgen(cb2, e);
265 expand(p, 0, " cmpl AR,AL\n");
266 cbgen(u, e);
267 deflab(s);
271 fldexpand(NODE *p, int cookie, char **cp)
273 CONSZ val;
275 if (p->n_op == ASSIGN)
276 p = p->n_left;
277 switch (**cp) {
278 case 'S':
279 printf("%d", UPKFSZ(p->n_rval));
280 break;
281 case 'H':
282 printf("%d", UPKFOFF(p->n_rval));
283 break;
284 case 'M':
285 case 'N':
286 val = (CONSZ)1 << UPKFSZ(p->n_rval);
287 --val;
288 val <<= UPKFOFF(p->n_rval);
289 printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff);
290 break;
291 default:
292 comperr("fldexpand");
294 return 1;
297 static void
298 bfext(NODE *p)
300 int ch = 0, sz = 0;
302 if (ISUNSIGNED(p->n_right->n_type))
303 return;
304 switch (p->n_right->n_type) {
305 case CHAR:
306 ch = 'b';
307 sz = 8;
308 break;
309 case SHORT:
310 ch = 'w';
311 sz = 16;
312 break;
313 case INT:
314 case LONG:
315 ch = 'l';
316 sz = 32;
317 break;
318 default:
319 comperr("bfext");
322 sz -= UPKFSZ(p->n_left->n_rval);
323 printf("\tshl%c $%d,", ch, sz);
324 adrput(stdout, getlr(p, 'D'));
325 printf("\n\tsar%c $%d,", ch, sz);
326 adrput(stdout, getlr(p, 'D'));
327 printf("\n");
330 /* long long bitfield assign */
331 static void
332 llbf(NODE *p)
334 NODE *q;
335 char buf[50];
336 CONSZ m, n;
337 int o, s;
338 int ml, mh, nl, nh;
340 q = p->n_left;
341 o = UPKFOFF(q->n_rval);
342 s = UPKFSZ(q->n_rval);
343 m = (CONSZ)1 << (s-1);
344 m--;
345 m = (m << 1) | 1;
346 m <<= o;
347 n = ~m;
349 ml = m & 0xffffffff;
350 nl = n & 0xffffffff;
351 mh = (m >> 32) & 0xffffffff;
352 nh = (n >> 32) & 0xffffffff;
354 #define S(...) snprintf(buf, sizeof buf, __VA_ARGS__); expand(p, 0, buf)
356 if (o < 32) { /* lower 32 buts */
357 S(" andl $0x%x,AL\n", nl);
358 S(" movl AR,A1\n");
359 S(" sall $%d,A1\n", o);
360 S(" andl $0x%x,A1\n", ml);
361 S(" orl A1,AL\n");
363 if ((o+s) >= 32) { /* upper 32 bits */
364 S(" andl $0x%x,UL\n", nh);
365 S(" movl UR,A1\n");
366 S(" sall $%d,A1\n", o);
367 S(" movl AR,U1\n");
368 S(" shrl $%d,U1\n", 32-o);
369 S(" orl U1,A1\n");
370 S(" andl $0x%x,A1\n", mh);
371 S(" orl A1,UL\n");
373 #undef S
374 // fwalk(p, e2print, 0);
380 * Push a structure on stack as argument.
381 * the scratch registers are already free here
383 static void
384 starg(NODE *p)
386 FILE *fp = stdout;
388 #if defined(MACHOABI)
389 fprintf(fp, " subl $%d,%%esp\n", p->n_stsize);
390 fprintf(fp, " subl $4,%%esp\n");
391 fprintf(fp, " pushl $%d\n", p->n_stsize);
392 expand(p, 0, " pushl AL\n");
393 expand(p, 0, " leal 12(%esp),A1\n");
394 expand(p, 0, " pushl A1\n");
395 if (kflag) {
396 fprintf(fp, " call L%s$stub\n", EXPREFIX "memcpy");
397 addstub(&stublist, EXPREFIX "memcpy");
398 } else {
399 fprintf(fp, " call %s\n", EXPREFIX "memcpy");
401 fprintf(fp, " addl $16,%%esp\n");
402 #else
403 fprintf(fp, " subl $%d,%%esp\n", (p->n_stsize+3) & ~3);
404 fprintf(fp, " pushl $%d\n", p->n_stsize);
405 expand(p, 0, " pushl AL\n");
406 expand(p, 0, " leal 8(%esp),A1\n");
407 expand(p, 0, " pushl A1\n");
408 fprintf(fp, " call %s%s\n", EXPREFIX "memcpy", kflag ? "@PLT" : "");
409 fprintf(fp, " addl $12,%%esp\n");
410 #endif
414 * Compare two floating point numbers.
416 static void
417 fcomp(NODE *p)
419 static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" };
421 if ((p->n_su & DORIGHT) == 0)
422 expand(p, 0, " fxch\n");
423 expand(p, 0, " fucomip %st(1),%st\n"); /* emit compare insn */
424 expand(p, 0, " fstp %st(0)\n"); /* pop fromstack */
426 if (p->n_op == NE || p->n_op == GT || p->n_op == GE)
427 expand(p, 0, " jp LC\n");
428 else if (p->n_op == EQ)
429 printf("\tjp 1f\n");
430 printf(" %s ", fpcb[p->n_op - EQ]);
431 expand(p, 0, "LC\n");
432 if (p->n_op == EQ)
433 printf("1:\n");
437 * Convert an unsigned long long to floating point number.
439 static void
440 ulltofp(NODE *p)
442 static int loadlab;
443 int jmplab;
445 if (loadlab == 0) {
446 loadlab = getlab2();
447 expand(p, 0, " .data\n");
448 printf(LABFMT ": .long 0,0x80000000,0x403f\n", loadlab);
449 expand(p, 0, " .text\n");
451 jmplab = getlab2();
452 expand(p, 0, " pushl UL\n pushl AL\n");
453 expand(p, 0, " fildq (%esp)\n");
454 expand(p, 0, " addl $8,%esp\n");
455 expand(p, 0, " cmpl $0,UL\n");
456 printf(" jge " LABFMT "\n", jmplab);
457 printf(" fldt " LABFMT "\n", loadlab);
458 printf(" faddp %%st,%%st(1)\n");
459 printf(LABFMT ":\n", jmplab);
462 static int
463 argsiz(NODE *p)
465 TWORD t = p->n_type;
467 if (t < LONGLONG || t == FLOAT || t > BTMASK)
468 return 4;
469 if (t == LONGLONG || t == ULONGLONG || t == DOUBLE)
470 return 8;
471 if (t == LDOUBLE)
472 return 12;
473 if (t == STRTY || t == UNIONTY)
474 return (p->n_stsize+3) & ~3;
475 comperr("argsiz");
476 return 0;
479 static void
480 fcast(NODE *p)
482 TWORD t = p->n_type;
483 int sz, c;
485 if (t >= p->n_left->n_type)
486 return; /* cast to more precision */
487 if (t == FLOAT)
488 sz = 4, c = 's';
489 else
490 sz = 8, c = 'l';
492 printf(" sub $%d,%%esp\n", sz);
493 printf(" fstp%c (%%esp)\n", c);
494 printf(" fld%c (%%esp)\n", c);
495 printf(" add $%d,%%esp\n", sz);
498 static void
499 llshft(NODE *p)
501 char *d[3];
503 if (p->n_op == LS) {
504 d[0] = "l", d[1] = "%eax", d[2] = "%edx";
505 } else
506 d[0] = "r", d[1] = "%edx", d[2] = "%eax";
508 printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]);
509 printf("\ts%s%sl %%cl,%s\n", p->n_op == RS &&
510 p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]);
511 printf("\ttestb $32,%%cl\n");
512 printf("\tje 1f\n");
513 printf("\tmovl %s,%s\n", d[1], d[2]);
514 if (p->n_op == RS && p->n_left->n_type == LONGLONG)
515 printf("\tsarl $31,%%edx\n");
516 else
517 printf("\txorl %s,%s\n",d[1],d[1]);
518 printf("1:\n");
521 void
522 zzzcode(NODE *p, int c)
524 NODE *l;
525 int pr, lr, s;
526 char *ch;
528 switch (c) {
529 case 'A': /* swap st0 and st1 if right is evaluated second */
530 if ((p->n_su & DORIGHT) == 0) {
531 if (logop(p->n_op))
532 printf(" fxch\n");
533 else
534 printf("r");
536 break;
538 case 'B': { /* packed bitfield ops */
539 int sz, off;
541 l = p->n_left;
542 sz = UPKFSZ(l->n_rval);
543 off = UPKFOFF(l->n_rval);
544 if (sz + off <= SZINT)
545 break;
546 /* lower already printed */
547 expand(p, INAREG, " movl AR,A1\n");
548 expand(p, INAREG, " andl $M,UL\n");
549 printf(" sarl $%d,", SZINT-off);
550 expand(p, INAREG, "A1\n");
551 expand(p, INAREG, " andl $N,A1\n");
552 expand(p, INAREG, " orl A1,UL\n");
554 break;
556 case 'C': /* remove from stack after subroutine call */
557 #ifdef notyet
558 if (p->n_left->n_flags & FSTDCALL)
559 break;
560 #endif
561 pr = p->n_qual;
562 if (p->n_op == STCALL || p->n_op == USTCALL)
563 pr += 4;
564 if (p->n_flags & FFPPOP)
565 printf(" fstp %%st(0)\n");
566 if (p->n_op == UCALL)
567 return; /* XXX remove ZC from UCALL */
568 if (pr)
569 printf(" addl $%d, %s\n", pr, rnames[ESP]);
570 break;
572 case 'D': /* Long long comparision */
573 twollcomp(p);
574 break;
576 case 'E': /* Perform bitfield sign-extension */
577 bfext(p);
578 break;
580 case 'F': /* Structure argument */
581 if (p->n_stalign != 0) /* already on stack */
582 starg(p);
583 break;
585 case 'G': /* Floating point compare */
586 fcomp(p);
587 break;
589 case 'H': /* assign of longlong between regs */
590 rmove(DECRA(p->n_right->n_reg, 0),
591 DECRA(p->n_left->n_reg, 0), LONGLONG);
592 break;
594 case 'I': /* float casts */
595 fcast(p);
596 break;
598 case 'J': /* convert unsigned long long to floating point */
599 ulltofp(p);
600 break;
602 case 'K': /* Load longlong reg into another reg */
603 rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG);
604 break;
606 case 'L': /* long long bitfield assign */
607 llbf(p);
608 break;
610 case 'M': /* Output sconv move, if needed */
611 l = getlr(p, 'L');
612 /* XXX fixneed: regnum */
613 pr = DECRA(p->n_reg, 0);
614 lr = DECRA(l->n_reg, 0);
615 if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) ||
616 (pr == CL && lr == ECX) || (pr == DL && lr == EDX))
618 else
619 printf(" movb %%%cl,%s\n",
620 rnames[lr][2], rnames[pr]);
621 l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */
622 break;
624 case 'N': /* output extended reg name */
625 printf("%s", rnames[getlr(p, '1')->n_rval]);
626 break;
628 case 'O': /* print out emulated ops */
629 pr = 16;
630 if (p->n_op == RS || p->n_op == LS) {
631 llshft(p);
632 break;
633 } else if (p->n_op == MUL) {
634 printf("\timull %%ecx, %%edx\n");
635 printf("\timull %%eax, %%esi\n");
636 printf("\taddl %%edx, %%esi\n");
637 printf("\tmull %%ecx\n");
638 printf("\taddl %%esi, %%edx\n");
639 break;
641 expand(p, INCREG, "\tpushl UR\n\tpushl AR\n");
642 expand(p, INCREG, "\tpushl UL\n\tpushl AL\n");
643 if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv";
644 else if (p->n_op == DIV) ch = "div";
645 else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod";
646 else if (p->n_op == MOD) ch = "mod";
647 else ch = 0, comperr("ZO");
648 #ifdef ELFABI
649 printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n",
650 ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]);
651 #else
652 printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n",
653 ch, pr, rnames[ESP]);
654 #endif
655 break;
657 case 'P': /* push hidden argument on stack */
658 printf("\tleal -%d(%%ebp),", stkpos);
659 adrput(stdout, getlr(p, '1'));
660 printf("\n\tpushl ");
661 adrput(stdout, getlr(p, '1'));
662 putchar('\n');
663 break;
665 case 'Q': /* emit struct assign */
667 * With <= 16 bytes, put out mov's, otherwise use movsb/w/l.
668 * esi/edi/ecx are available.
669 * XXX should not need esi/edi if not rep movsX.
670 * XXX can save one insn if src ptr in reg.
672 switch (p->n_stsize) {
673 case 1:
674 expand(p, INAREG, " movb (%esi),%cl\n");
675 expand(p, INAREG, " movb %cl,AL\n");
676 break;
677 case 2:
678 expand(p, INAREG, " movw (%esi),%cx\n");
679 expand(p, INAREG, " movw %cx,AL\n");
680 break;
681 case 4:
682 expand(p, INAREG, " movl (%esi),%ecx\n");
683 expand(p, INAREG, " movl %ecx,AL\n");
684 break;
685 default:
686 expand(p, INAREG, " leal AL,%edi\n");
687 if (p->n_stsize <= 16 && (p->n_stsize & 3) == 0) {
688 printf(" movl (%%esi),%%ecx\n");
689 printf(" movl %%ecx,(%%edi)\n");
690 printf(" movl 4(%%esi),%%ecx\n");
691 printf(" movl %%ecx,4(%%edi)\n");
692 if (p->n_stsize > 8) {
693 printf(" movl 8(%%esi),%%ecx\n");
694 printf(" movl %%ecx,8(%%edi)\n");
696 if (p->n_stsize == 16) {
697 printf("\tmovl 12(%%esi),%%ecx\n");
698 printf("\tmovl %%ecx,12(%%edi)\n");
700 } else {
701 if (p->n_stsize > 4) {
702 printf("\tmovl $%d,%%ecx\n",
703 p->n_stsize >> 2);
704 printf(" rep movsl\n");
706 if (p->n_stsize & 2)
707 printf(" movsw\n");
708 if (p->n_stsize & 1)
709 printf(" movsb\n");
711 break;
713 break;
715 case 'S': /* emit eventual move after cast from longlong */
716 pr = DECRA(p->n_reg, 0);
717 lr = p->n_left->n_rval;
718 switch (p->n_type) {
719 case CHAR:
720 case UCHAR:
721 if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' &&
722 rnames[pr][1] == rnames[lr][1])
723 break;
724 if (rnames[lr][2] == 'x') {
725 printf("\tmovb %%%cl,%s\n",
726 rnames[lr][1], rnames[pr]);
727 break;
729 /* Must go via stack */
730 s = BITOOR(freetemp(1));
731 printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s);
732 printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]);
733 // comperr("SCONV1 %s->%s", rnames[lr], rnames[pr]);
734 break;
736 case SHORT:
737 case USHORT:
738 if (rnames[lr][1] == rnames[pr][2] &&
739 rnames[lr][2] == rnames[pr][3])
740 break;
741 printf("\tmovw %%%c%c,%%%s\n",
742 rnames[lr][1], rnames[lr][2], rnames[pr]+2);
743 break;
744 case INT:
745 case UNSIGNED:
746 if (rnames[lr][1] == rnames[pr][2] &&
747 rnames[lr][2] == rnames[pr][3])
748 break;
749 printf("\tmovl %%e%c%c,%s\n",
750 rnames[lr][1], rnames[lr][2], rnames[pr]);
751 break;
753 default:
754 if (rnames[lr][1] == rnames[pr][2] &&
755 rnames[lr][2] == rnames[pr][3])
756 break;
757 comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]);
758 break;
760 break;
762 default:
763 comperr("zzzcode %c", c);
767 /*ARGSUSED*/
769 rewfld(NODE *p)
771 return(1);
774 int canaddr(NODE *);
776 canaddr(NODE *p)
778 int o = p->n_op;
780 if (o==NAME || o==REG || o==ICON || o==OREG ||
781 (o==UMUL && shumul(p->n_left, SOREG)))
782 return(1);
783 return(0);
787 * Does the bitfield shape match?
790 flshape(NODE *p)
792 int o = p->n_op;
794 if (o == OREG || o == REG || o == NAME)
795 return SRDIR; /* Direct match */
796 if (o == UMUL && shumul(p->n_left, SOREG))
797 return SROREG; /* Convert into oreg */
798 return SRREG; /* put it into a register */
801 /* INTEMP shapes must not contain any temporary registers */
802 /* XXX should this go away now? */
804 shtemp(NODE *p)
806 return 0;
807 #if 0
808 int r;
810 if (p->n_op == STARG )
811 p = p->n_left;
813 switch (p->n_op) {
814 case REG:
815 return (!istreg(p->n_rval));
817 case OREG:
818 r = p->n_rval;
819 if (R2TEST(r)) {
820 if (istreg(R2UPK1(r)))
821 return(0);
822 r = R2UPK2(r);
824 return (!istreg(r));
826 case UMUL:
827 p = p->n_left;
828 return (p->n_op != UMUL && shtemp(p));
831 if (optype(p->n_op) != LTYPE)
832 return(0);
833 return(1);
834 #endif
837 void
838 adrcon(CONSZ val)
840 printf("$" CONFMT, val);
843 void
844 conput(FILE *fp, NODE *p)
846 int val = (int)p->n_lval;
848 switch (p->n_op) {
849 case ICON:
850 if (p->n_name[0] != '\0') {
851 fprintf(fp, "%s", p->n_name);
852 if (val)
853 fprintf(fp, "+%d", val);
854 } else
855 fprintf(fp, "%d", val);
856 return;
858 default:
859 comperr("illegal conput, p %p", p);
863 /*ARGSUSED*/
864 void
865 insput(NODE *p)
867 comperr("insput");
871 * Write out the upper address, like the upper register of a 2-register
872 * reference, or the next memory location.
874 void
875 upput(NODE *p, int size)
878 if (p->n_op == FLD)
879 p = p->n_left;
881 size /= SZCHAR;
882 switch (p->n_op) {
883 case REG:
884 fprintf(stdout, "%%%s", &rnames[p->n_rval][3]);
885 break;
887 case NAME:
888 case OREG:
889 p->n_lval += size;
890 adrput(stdout, p);
891 p->n_lval -= size;
892 break;
893 case ICON:
894 fprintf(stdout, "$" CONFMT, p->n_lval >> 32);
895 break;
896 default:
897 comperr("upput bad op %d size %d", p->n_op, size);
901 void
902 adrput(FILE *io, NODE *p)
904 int r;
905 /* output an address, with offsets, from p */
907 if (p->n_op == FLD)
908 p = p->n_left;
910 switch (p->n_op) {
912 case NAME:
913 if (p->n_name[0] != '\0') {
914 fputs(p->n_name, io);
915 if (p->n_lval != 0)
916 fprintf(io, "+" CONFMT, p->n_lval);
917 } else
918 fprintf(io, CONFMT, p->n_lval);
919 return;
921 case OREG:
922 r = p->n_rval;
923 if (p->n_name[0])
924 printf("%s%s", p->n_name, p->n_lval ? "+" : "");
925 if (p->n_lval)
926 fprintf(io, "%d", (int)p->n_lval);
927 if (R2TEST(r)) {
928 fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)],
929 rnames[R2UPK2(r)]);
930 } else
931 fprintf(io, "(%s)", rnames[p->n_rval]);
932 return;
933 case ICON:
934 #ifdef PCC_DEBUG
935 /* Sanitycheck for PIC, to catch adressable constants */
936 if (kflag && p->n_name[0] && 0) {
937 static int foo;
939 if (foo++ == 0) {
940 printf("\nfailing...\n");
941 fwalk(p, e2print, 0);
942 comperr("pass2 conput");
945 #endif
946 /* addressable value of the constant */
947 fputc('$', io);
948 conput(io, p);
949 return;
951 case REG:
952 switch (p->n_type) {
953 case LONGLONG:
954 case ULONGLONG:
955 fprintf(io, "%%%c%c%c", rnames[p->n_rval][0],
956 rnames[p->n_rval][1], rnames[p->n_rval][2]);
957 break;
958 case SHORT:
959 case USHORT:
960 fprintf(io, "%%%s", &rnames[p->n_rval][2]);
961 break;
962 default:
963 fprintf(io, "%s", rnames[p->n_rval]);
965 return;
967 default:
968 comperr("illegal address, op %d, node %p", p->n_op, p);
969 return;
974 static char *
975 ccbranches[] = {
976 "je", /* jumpe */
977 "jne", /* jumpn */
978 "jle", /* jumple */
979 "jl", /* jumpl */
980 "jge", /* jumpge */
981 "jg", /* jumpg */
982 "jbe", /* jumple (jlequ) */
983 "jb", /* jumpl (jlssu) */
984 "jae", /* jumpge (jgequ) */
985 "ja", /* jumpg (jgtru) */
989 /* printf conditional and unconditional branches */
990 void
991 cbgen(int o, int lab)
993 if (o < EQ || o > UGT)
994 comperr("bad conditional branch: %s", opst[o]);
995 printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab);
998 static void
999 fixcalls(NODE *p, void *arg)
1001 /* Prepare for struct return by allocating bounce space on stack */
1002 switch (p->n_op) {
1003 case STCALL:
1004 case USTCALL:
1005 if (p->n_stsize+p2autooff > stkpos)
1006 stkpos = p->n_stsize+p2autooff;
1007 break;
1008 case LS:
1009 case RS:
1010 if (p->n_type != LONGLONG && p->n_type != ULONGLONG)
1011 break;
1012 if (p->n_right->n_op == ICON) /* constants must be char */
1013 p->n_right->n_type = CHAR;
1014 break;
1019 * Must store floats in memory if there are two function calls involved.
1021 static int
1022 storefloat(struct interpass *ip, NODE *p)
1024 int l, r;
1026 switch (optype(p->n_op)) {
1027 case BITYPE:
1028 l = storefloat(ip, p->n_left);
1029 r = storefloat(ip, p->n_right);
1030 if (p->n_op == CM)
1031 return 0; /* arguments, don't care */
1032 if (callop(p->n_op))
1033 return 1; /* found one */
1034 #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \
1035 (p)->n_type == LDOUBLE)
1036 if (ISF(p->n_left) && ISF(p->n_right) && l && r) {
1037 /* must store one. store left */
1038 struct interpass *nip;
1039 TWORD t = p->n_left->n_type;
1040 NODE *ll;
1041 int off;
1043 off = BITOOR(freetemp(szty(t)));
1044 ll = mklnode(OREG, off, FPREG, t);
1045 nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t));
1046 p->n_left = mklnode(OREG, off, FPREG, t);
1047 DLIST_INSERT_BEFORE(ip, nip, qelem);
1049 return l|r;
1051 case UTYPE:
1052 l = storefloat(ip, p->n_left);
1053 if (callop(p->n_op))
1054 l = 1;
1055 return l;
1056 default:
1057 return 0;
1061 static void
1062 outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
1064 struct interpass *ip2;
1065 NODE *q, *r;
1066 int i;
1068 for (i = 0; i < num; i++)
1069 if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT)))
1070 break;
1071 if (i == num)
1072 return;
1073 q = ary[i]->n_left;
1074 r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
1075 ary[i]->n_left = tcopy(r);
1076 ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type));
1077 DLIST_INSERT_AFTER(ip, ip2, qelem);
1080 static void
1081 infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c)
1083 struct interpass *ip2;
1084 NODE *q, *r;
1085 int i;
1087 for (i = 0; i < num; i++)
1088 if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0)
1089 break;
1090 if (i == num)
1091 return;
1092 q = ary[i]->n_left;
1093 q = (cwp[i] & XASMINOUT) ? tcopy(q) : q;
1094 r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type);
1095 if ((cwp[i] & XASMINOUT) == 0)
1096 ary[i]->n_left = tcopy(r);
1097 ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type));
1098 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1102 * Extract float args to XASM and ensure that they are put on the stack
1103 * in correct order.
1104 * This should be done sow other way.
1106 static void
1107 fixxfloat(struct interpass *ip, NODE *p)
1109 NODE *w, **ary;
1110 int nn, i, c, *cwp;
1112 nn = 1;
1113 w = p->n_left;
1114 if (w->n_op == ICON && w->n_type == STRTY)
1115 return;
1116 /* index all xasm args first */
1117 for (; w->n_op == CM; w = w->n_left)
1118 nn++;
1119 ary = tmpcalloc(nn * sizeof(NODE *));
1120 cwp = tmpcalloc(nn * sizeof(int));
1121 for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) {
1122 ary[i] = w->n_right;
1123 cwp[i] = xasmcode(ary[i]->n_name);
1124 i++;
1126 ary[i] = w;
1127 cwp[i] = xasmcode(ary[i]->n_name);
1128 for (i = 0; i < nn; i++)
1129 if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u')
1130 break;
1131 if (i == nn)
1132 return;
1134 for (i = 0; i < nn; i++) {
1135 c = XASMVAL(cwp[i]);
1136 if (c >= '0' && c <= '9')
1137 cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']);
1139 infargs(ip, ary, nn, cwp, 'u');
1140 infargs(ip, ary, nn, cwp, 't');
1141 outfargs(ip, ary, nn, cwp, 't');
1142 outfargs(ip, ary, nn, cwp, 'u');
1145 void
1146 myreader(struct interpass *ipole)
1148 struct interpass *ip;
1150 stkpos = p2autooff;
1151 DLIST_FOREACH(ip, ipole, qelem) {
1152 if (ip->type != IP_NODE)
1153 continue;
1154 walkf(ip->ip_node, fixcalls, 0);
1155 storefloat(ip, ip->ip_node);
1156 if (ip->ip_node->n_op == XASM)
1157 fixxfloat(ip, ip->ip_node);
1159 if (stkpos > p2autooff)
1160 p2autooff = stkpos;
1161 if (stkpos > p2maxautooff)
1162 p2maxautooff = stkpos;
1163 if (x2debug)
1164 printip(ipole);
1168 * Remove some PCONVs after OREGs are created.
1170 static void
1171 pconv2(NODE *p, void *arg)
1173 NODE *q;
1175 if (p->n_op == PLUS) {
1176 if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) {
1177 if (p->n_right->n_op != ICON)
1178 return;
1179 if (p->n_left->n_op != PCONV)
1180 return;
1181 if (p->n_left->n_left->n_op != OREG)
1182 return;
1183 q = p->n_left->n_left;
1184 nfree(p->n_left);
1185 p->n_left = q;
1187 * This will be converted to another OREG later.
1193 void
1194 mycanon(NODE *p)
1196 walkf(p, pconv2, 0);
1199 void
1200 myoptim(struct interpass *ip)
1204 static char rl[] =
1205 { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI };
1206 static char rh[] =
1207 { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI };
1209 void
1210 rmove(int s, int d, TWORD t)
1212 int sl, sh, dl, dh;
1214 switch (t) {
1215 case LONGLONG:
1216 case ULONGLONG:
1217 #if 1
1218 sl = rl[s-EAXEDX];
1219 sh = rh[s-EAXEDX];
1220 dl = rl[d-EAXEDX];
1221 dh = rh[d-EAXEDX];
1223 /* sanity checks, remove when satisfied */
1224 if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 ||
1225 memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0)
1226 comperr("rmove source error");
1227 if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 ||
1228 memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0)
1229 comperr("rmove dest error");
1230 #define SW(x,y) { int i = x; x = y; y = i; }
1231 if (sh == dl) {
1232 /* Swap if overwriting */
1233 SW(sl, sh);
1234 SW(dl, dh);
1236 if (sl != dl)
1237 printf(" movl %s,%s\n", rnames[sl], rnames[dl]);
1238 if (sh != dh)
1239 printf(" movl %s,%s\n", rnames[sh], rnames[dh]);
1240 #else
1241 if (memcmp(rnames[s], rnames[d], 3) != 0)
1242 printf(" movl %%%c%c%c,%%%c%c%c\n",
1243 rnames[s][0],rnames[s][1],rnames[s][2],
1244 rnames[d][0],rnames[d][1],rnames[d][2]);
1245 if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0)
1246 printf(" movl %%%c%c%c,%%%c%c%c\n",
1247 rnames[s][3],rnames[s][4],rnames[s][5],
1248 rnames[d][3],rnames[d][4],rnames[d][5]);
1249 #endif
1250 break;
1251 case CHAR:
1252 case UCHAR:
1253 printf(" movb %s,%s\n", rnames[s], rnames[d]);
1254 break;
1255 case FLOAT:
1256 case DOUBLE:
1257 case LDOUBLE:
1258 #ifdef notdef
1259 /* a=b()*c(); will generate this */
1260 comperr("bad float rmove: %d %d", s, d);
1261 #endif
1262 break;
1263 default:
1264 printf(" movl %s,%s\n", rnames[s], rnames[d]);
1269 * For class c, find worst-case displacement of the number of
1270 * registers in the array r[] indexed by class.
1273 COLORMAP(int c, int *r)
1275 int num;
1277 switch (c) {
1278 case CLASSA:
1279 num = r[CLASSB] > 4 ? 4 : r[CLASSB];
1280 num += 2*r[CLASSC];
1281 num += r[CLASSA];
1282 return num < 6;
1283 case CLASSB:
1284 num = r[CLASSA];
1285 num += 2*r[CLASSC];
1286 num += r[CLASSB];
1287 return num < 4;
1288 case CLASSC:
1289 num = r[CLASSA];
1290 num += r[CLASSB] > 4 ? 4 : r[CLASSB];
1291 num += 2*r[CLASSC];
1292 return num < 5;
1293 case CLASSD:
1294 return r[CLASSD] < DREGCNT;
1296 return 0; /* XXX gcc */
1299 char *rnames[] = {
1300 "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp",
1301 "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh",
1302 "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx",
1303 "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi",
1304 "ebxesi", "ebxedi", "esiedi",
1305 "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7",
1309 * Return a class suitable for a specific type.
1312 gclass(TWORD t)
1314 if (t == CHAR || t == UCHAR)
1315 return CLASSB;
1316 if (t == LONGLONG || t == ULONGLONG)
1317 return CLASSC;
1318 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
1319 return CLASSD;
1320 return CLASSA;
1324 * Calculate argument sizes.
1326 void
1327 lastcall(NODE *p)
1329 NODE *op = p;
1330 int size = 0;
1332 p->n_qual = 0;
1333 if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL)
1334 return;
1335 for (p = p->n_right; p->n_op == CM; p = p->n_left)
1336 size += argsiz(p->n_right);
1337 size += argsiz(p);
1338 #if defined(ELFABI)
1339 if (kflag)
1340 size -= 4;
1341 #endif
1344 #if defined(MACHOABI)
1345 int newsize = (size + 15) & ~15; /* stack alignment */
1346 int align = newsize-size;
1348 if (align != 0)
1349 printf(" subl $%d,%%esp\n", align);
1351 size=newsize;
1352 #endif
1354 op->n_qual = size; /* XXX */
1358 * Special shapes.
1361 special(NODE *p, int shape)
1363 int o = p->n_op;
1365 switch (shape) {
1366 case SFUNCALL:
1367 if (o == STCALL || o == USTCALL)
1368 return SRREG;
1369 break;
1370 case SPCON:
1371 if (o != ICON || p->n_name[0] ||
1372 p->n_lval < 0 || p->n_lval > 0x7fffffff)
1373 break;
1374 return SRDIR;
1375 case SMIXOR:
1376 return tshape(p, SZERO);
1377 case SMILWXOR:
1378 if (o != ICON || p->n_name[0] ||
1379 p->n_lval == 0 || p->n_lval & 0xffffffff)
1380 break;
1381 return SRDIR;
1382 case SMIHWXOR:
1383 if (o != ICON || p->n_name[0] ||
1384 p->n_lval == 0 || (p->n_lval >> 32) != 0)
1385 break;
1386 return SRDIR;
1388 return SRNOPE;
1392 * Target-dependent command-line options.
1394 void
1395 mflags(char *str)
1400 * Do something target-dependent for xasm arguments.
1403 myxasm(struct interpass *ip, NODE *p)
1405 struct interpass *ip2;
1406 int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 };
1407 NODE *in = 0, *ut = 0;
1408 TWORD t;
1409 char *w;
1410 int reg;
1411 int c, cw, v;
1413 cw = xasmcode(p->n_name);
1414 if (cw & (XASMASG|XASMINOUT))
1415 ut = p->n_left;
1416 if ((cw & XASMASG) == 0)
1417 in = p->n_left;
1419 c = XASMVAL(cw);
1420 switch (c) {
1421 case 'D': reg = EDI; break;
1422 case 'S': reg = ESI; break;
1423 case 'a': reg = EAX; break;
1424 case 'b': reg = EBX; break;
1425 case 'c': reg = ECX; break;
1426 case 'd': reg = EDX; break;
1428 case 't':
1429 case 'u':
1430 p->n_name = tmpstrdup(p->n_name);
1431 w = strchr(p->n_name, XASMVAL(cw));
1432 *w = 'r'; /* now reg */
1433 return 1;
1435 case 'A': reg = EAXEDX; break;
1436 case 'q': {
1437 /* Set edges in MYSETXARG */
1438 if (p->n_left->n_op == REG || p->n_left->n_op == TEMP)
1439 return 1;
1440 t = p->n_left->n_type;
1441 if (in && ut)
1442 in = tcopy(in);
1443 p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t);
1444 if (ut) {
1445 ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1446 DLIST_INSERT_AFTER(ip, ip2, qelem);
1448 if (in) {
1449 ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1450 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1452 return 1;
1455 case 'I':
1456 case 'J':
1457 case 'K':
1458 case 'L':
1459 case 'M':
1460 case 'N':
1461 if (p->n_left->n_op != ICON)
1462 uerror("xasm arg not constant");
1463 v = p->n_left->n_lval;
1464 if ((c == 'K' && v < -128) ||
1465 (c == 'L' && v != 0xff && v != 0xffff) ||
1466 (c != 'K' && v < 0) ||
1467 (v > Cmax[c-'I']))
1468 uerror("xasm val out of range");
1469 p->n_name = "i";
1470 return 1;
1472 default:
1473 return 0;
1475 /* If there are requested either memory or register, delete memory */
1476 w = p->n_name = tmpstrdup(p->n_name);
1477 if (*w == '=')
1478 w++;
1479 *w++ = 'r';
1480 *w = 0;
1482 t = p->n_left->n_type;
1483 if (reg == EAXEDX) {
1484 p->n_label = CLASSC;
1485 } else {
1486 p->n_label = CLASSA;
1487 if (t == CHAR || t == UCHAR) {
1488 p->n_label = CLASSB;
1489 reg = reg * 2 + 8;
1492 if (t == FLOAT || t == DOUBLE || t == LDOUBLE) {
1493 p->n_label = CLASSD;
1494 reg += 037;
1497 if (in && ut)
1498 in = tcopy(in);
1499 p->n_left = mklnode(REG, 0, reg, t);
1500 if (ut) {
1501 ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t));
1502 DLIST_INSERT_AFTER(ip, ip2, qelem);
1504 if (in) {
1505 ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t));
1506 DLIST_INSERT_BEFORE(ip, ip2, qelem);
1508 return 1;
1511 void
1512 targarg(char *w, void *arg)
1514 NODE **ary = arg;
1515 NODE *p, *q;
1517 if (ary[(int)w[1]-'0'] == 0)
1518 p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */
1519 else
1520 p = ary[(int)w[1]-'0']->n_left;
1521 if (optype(p->n_op) != LTYPE)
1522 comperr("bad xarg op %d", p->n_op);
1523 q = tcopy(p);
1524 if (q->n_op == REG) {
1525 if (*w == 'k') {
1526 q->n_type = INT;
1527 } else if (*w != 'w') {
1528 if (q->n_type > UCHAR) {
1529 regno(q) = regno(q)*2+8;
1530 if (*w == 'h')
1531 regno(q)++;
1533 q->n_type = INT;
1534 } else
1535 q->n_type = SHORT;
1537 adrput(stdout, q);
1538 tfree(q);
1542 * target-specific conversion of numeric arguments.
1545 numconv(void *ip, void *p1, void *q1)
1547 NODE *p = p1, *q = q1;
1548 int cw = xasmcode(q->n_name);
1550 switch (XASMVAL(cw)) {
1551 case 'a':
1552 case 'b':
1553 case 'c':
1554 case 'd':
1555 p->n_name = tmpcalloc(2);
1556 p->n_name[0] = (char)XASMVAL(cw);
1557 return 1;
1558 default:
1559 return 0;
1563 static struct {
1564 char *name; int num;
1565 } xcr[] = {
1566 { "eax", EAX },
1567 { "ebx", EBX },
1568 { "ecx", ECX },
1569 { "edx", EDX },
1570 { "esi", ESI },
1571 { "edi", EDI },
1572 { "ax", EAX },
1573 { "bx", EBX },
1574 { "cx", ECX },
1575 { "dx", EDX },
1576 { NULL, 0 },
1580 * Check for other names of the xasm constraints registers.
1584 * Check for other names of the xasm constraints registers.
1586 int xasmconstregs(char *s)
1588 int i;
1590 if (strncmp(s, "st", 2) == 0) {
1591 int off =0;
1592 if (s[2] == '(' && s[4] == ')')
1593 off = s[3] - '0';
1594 return ESIEDI + 1 + off;
1597 for (i = 0; xcr[i].name; i++)
1598 if (strcmp(xcr[i].name, s) == 0)
1599 return xcr[i].num;
1600 return -1;