* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / arch / mips / code.c
blob79f2140cbe9352570f6eb88269c25fd9003df3db
1 /* $Id: code.c,v 1.17 2010/09/19 14:01:35 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.
31 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
32 * Simon Olsson (simols-1@student.ltu.se) 2005.
35 #include <assert.h>
36 #include "pass1.h"
39 * Define everything needed to print out some data (or text).
40 * This means segment, alignment, visibility, etc.
42 void
43 defloc(struct symtab *sp)
45 static char *loctbl[] = { "text", "data", "section .rodata" };
46 static int lastloc = -1;
47 TWORD t;
48 char *n;
49 int s;
51 if (sp == NULL) {
52 lastloc = -1;
53 return;
55 t = sp->stype;
56 s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
57 lastloc = s;
58 if (s == PROG)
59 return; /* text is written in prologue() */
60 if (s != lastloc)
61 printf(" .%s\n", loctbl[s]);
62 printf(" .p2align %d\n", ispow2(talign(t, sp->sap)));
63 n = sp->soname ? sp->soname : sp->sname;
64 if (sp->sclass == EXTDEF)
65 printf(" .globl %s\n", n);
66 if (sp->slevel == 0) {
67 #ifdef USE_GAS
68 printf("\t.type %s,@object\n", n);
69 printf("\t.size %s," CONFMT "\n", n,
70 tsize(sp->stype, sp->sdf, sp->sap));
71 #endif
72 printf("%s:\n", n);
73 } else
74 printf(LABFMT ":\n", sp->soffset);
78 #ifdef notdef
80 * cause the alignment to become a multiple of n
81 * never called for text segment.
83 void
84 defalign(int n)
86 n = ispow2(n / SZCHAR);
87 if (n == -1)
88 cerror("defalign: n != 2^i");
89 printf("\t.p2align %d\n", n);
93 * define the current location as the name p->sname
94 * never called for text segment.
96 void
97 defnam(struct symtab *p)
99 char *c = p->soname;
101 if (p->sclass == EXTDEF)
102 printf("\t.globl %s\n", c);
103 #ifdef USE_GAS
104 printf("\t.type %s,@object\n", c);
105 printf("\t.size %s," CONFMT "\n", c, tsize(p->stype, p->sdf, p->sap));
106 #endif
107 printf("%s:\n", c);
109 #endif
111 static int rvnr;
114 * code for the end of a function
115 * deals with struct return here
117 void
118 efcode()
120 NODE *p, *q;
121 int tempnr;
122 int ty;
124 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
125 return;
127 ty = cftnsp->stype - FTN;
129 q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
130 q->n_rval = V0;
131 p = tempnode(0, INCREF(ty), 0, cftnsp->sap);
132 tempnr = regno(p);
133 p = buildtree(ASSIGN, p, q);
134 ecomp(p);
136 q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
137 q = buildtree(UMUL, q, NIL);
139 p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
140 p = buildtree(UMUL, p, NIL);
142 p = buildtree(ASSIGN, p, q);
143 ecomp(p);
145 q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
146 p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap);
147 p->n_rval = V0;
148 p = buildtree(ASSIGN, p, q);
149 ecomp(p);
152 /* Put a symbol in a temporary
153 * used by bfcode() and its helpers */
154 static void
155 putintemp(struct symtab *sym)
157 NODE *p;
158 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
159 p = buildtree(ASSIGN, p, nametree(sym));
160 sym->soffset = regno(p->n_left);
161 sym->sflags |= STNODE;
162 ecomp(p);
165 /* setup the hidden pointer to struct return parameter
166 * used by bfcode() */
167 static void
168 param_retptr(void)
170 NODE *p, *q;
172 p = tempnode(0, PTR+STRTY, 0, cftnsp->sap);
173 rvnr = regno(p);
174 q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
175 q->n_rval = A0;
176 p = buildtree(ASSIGN, p, q);
177 ecomp(p);
180 /* setup struct parameter
181 * push the registers out to memory
182 * used by bfcode() */
183 static void
184 param_struct(struct symtab *sym, int *regp)
186 int reg = *regp;
187 NODE *p, *q;
188 int navail;
189 int sz;
190 int off;
191 int num;
192 int i;
194 navail = nargregs - (reg - A0);
195 sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT;
196 off = ARGINIT/SZINT + (reg - A0);
197 num = sz > navail ? navail : sz;
198 for (i = 0; i < num; i++) {
199 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
200 q->n_rval = reg++;
201 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
202 p->n_rval = FP;
203 p = block(PLUS, p, bcon(4*off++), INT, 0, MKAP(INT));
204 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
205 p = buildtree(ASSIGN, p, q);
206 ecomp(p);
209 *regp = reg;
212 /* setup a 64-bit parameter (double/ldouble/longlong)
213 * used by bfcode() */
214 static void
215 param_64bit(struct symtab *sym, int *regp, int dotemps)
217 int reg = *regp;
218 NODE *p, *q;
219 int navail;
221 /* alignment */
222 ++reg;
223 reg &= ~1;
225 navail = nargregs - (reg - A0);
227 if (navail < 2) {
228 /* would have appeared half in registers/half
229 * on the stack, but alignment ensures it
230 * appears on the stack */
231 if (dotemps)
232 putintemp(sym);
233 *regp = reg;
234 return;
237 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
238 q->n_rval = A0A1 + (reg - A0);
239 if (dotemps) {
240 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
241 sym->soffset = regno(p);
242 sym->sflags |= STNODE;
243 } else {
244 p = nametree(sym);
246 p = buildtree(ASSIGN, p, q);
247 ecomp(p);
248 *regp = reg + 2;
251 /* setup a 32-bit param on the stack
252 * used by bfcode() */
253 static void
254 param_32bit(struct symtab *sym, int *regp, int dotemps)
256 NODE *p, *q;
258 q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap);
259 q->n_rval = (*regp)++;
260 if (dotemps) {
261 p = tempnode(0, sym->stype, sym->sdf, sym->sap);
262 sym->soffset = regno(p);
263 sym->sflags |= STNODE;
264 } else {
265 p = nametree(sym);
267 p = buildtree(ASSIGN, p, q);
268 ecomp(p);
272 * XXX This is a hack. We cannot have (l)doubles in more than one
273 * register class. So we bounce them in and out of temps to
274 * move them in and out of the right registers.
276 static void
277 param_double(struct symtab *sym, int *regp, int dotemps)
279 int reg = *regp;
280 NODE *p, *q, *t;
281 int navail;
282 int tmpnr;
284 /* alignment */
285 ++reg;
286 reg &= ~1;
288 navail = nargregs - (reg - A0);
290 if (navail < 2) {
291 /* would have appeared half in registers/half
292 * on the stack, but alignment ensures it
293 * appears on the stack */
294 if (dotemps)
295 putintemp(sym);
296 *regp = reg;
297 return;
300 t = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
301 tmpnr = regno(t);
302 q = block(REG, NIL, NIL, LONGLONG, 0, MKAP(LONGLONG));
303 q->n_rval = A0A1 + (reg - A0);
304 p = buildtree(ASSIGN, t, q);
305 ecomp(p);
307 if (dotemps) {
308 sym->soffset = tmpnr;
309 sym->sflags |= STNODE;
310 } else {
311 q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
312 p = nametree(sym);
313 p = buildtree(ASSIGN, p, q);
314 ecomp(p);
316 *regp = reg + 2;
320 * XXX This is a hack. We cannot have floats in more than one
321 * register class. So we bounce them in and out of temps to
322 * move them in and out of the right registers.
324 static void
325 param_float(struct symtab *sym, int *regp, int dotemps)
327 NODE *p, *q, *t;
328 int tmpnr;
330 t = tempnode(0, INT, 0, MKAP(INT));
331 tmpnr = regno(t);
332 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
333 q->n_rval = (*regp)++;
334 p = buildtree(ASSIGN, t, q);
335 ecomp(p);
337 if (dotemps) {
338 sym->soffset = tmpnr;
339 sym->sflags |= STNODE;
340 } else {
341 q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap);
342 p = nametree(sym);
343 p = buildtree(ASSIGN, p, q);
344 ecomp(p);
349 * code for the beginning of a function; a is an array of
350 * indices in symtab for the arguments; n is the number
352 void
353 bfcode(struct symtab **sp, int cnt)
355 union arglist *usym;
356 int lastreg = A0 + nargregs - 1;
357 int saveallargs = 0;
358 int i, reg;
361 * Detect if this function has ellipses and save all
362 * argument register onto stack.
364 usym = cftnsp->sdf->dfun;
365 while (usym && usym->type != TNULL) {
366 if (usym->type == TELLIPSIS) {
367 saveallargs = 1;
368 break;
370 ++usym;
373 reg = A0;
375 /* assign hidden return structure to temporary */
376 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
377 param_retptr();
378 ++reg;
381 /* recalculate the arg offset and create TEMP moves */
382 for (i = 0; i < cnt; i++) {
384 if ((reg > lastreg) && !xtemps)
385 break;
386 else if (reg > lastreg)
387 putintemp(sp[i]);
388 else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY)
389 param_struct(sp[i], &reg);
390 else if (DEUNSIGN(sp[i]->stype) == LONGLONG)
391 param_64bit(sp[i], &reg, xtemps && !saveallargs);
392 else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE)
393 param_double(sp[i], &reg, xtemps && !saveallargs);
394 else if (sp[i]->stype == FLOAT)
395 param_float(sp[i], &reg, xtemps && !saveallargs);
396 else
397 param_32bit(sp[i], &reg, xtemps && !saveallargs);
400 /* if saveallargs, save the rest of the args onto the stack */
401 if (!saveallargs)
402 return;
403 while (reg <= lastreg) {
404 NODE *p, *q;
405 int off = ARGINIT/SZINT + (reg - A0);
406 q = block(REG, NIL, NIL, INT, 0, MKAP(INT));
407 q->n_rval = reg++;
408 p = block(REG, NIL, NIL, INT, 0, MKAP(INT));
409 p->n_rval = FP;
410 p = block(PLUS, p, bcon(4*off), INT, 0, MKAP(INT));
411 p = block(UMUL, p, NIL, INT, 0, MKAP(INT));
412 p = buildtree(ASSIGN, p, q);
413 ecomp(p);
420 * by now, the automatics and register variables are allocated
422 void
423 bccode()
425 SETOFF(autooff, SZINT);
428 /* called just before final exit */
429 /* flag is 1 if errors, 0 if none */
430 void
431 ejobcode(int flag )
435 void
436 bjobcode()
438 printf("\t.section .mdebug.abi32\n");
439 printf("\t.previous\n");
440 printf("\t.abicalls\n");
443 #ifdef notdef
445 * Print character t at position i in one string, until t == -1.
446 * Locctr & label is already defined.
448 void
449 bycode(int t, int i)
451 static int lastoctal = 0;
453 /* put byte i+1 in a string */
455 if (t < 0) {
456 if (i != 0)
457 puts("\\000\"");
458 } else {
459 if (i == 0)
460 printf("\t.ascii \"");
461 if (t == 0)
462 return;
463 else if (t == '\\' || t == '"') {
464 lastoctal = 0;
465 putchar('\\');
466 putchar(t);
467 } else if (t == 011) {
468 printf("\\t");
469 } else if (t == 012) {
470 printf("\\n");
471 } else if (t < 040 || t >= 0177) {
472 lastoctal++;
473 printf("\\%o",t);
474 } else if (lastoctal && '0' <= t && t <= '9') {
475 lastoctal = 0;
476 printf("\"\n\t.ascii \"%c", t);
477 } else {
478 lastoctal = 0;
479 putchar(t);
483 #endif
486 * return the alignment of field of type t
489 fldal(unsigned int t)
491 uerror("illegal field type");
492 return(ALINT);
495 /* fix up type of field p */
496 void
497 fldty(struct symtab *p)
502 * XXX - fix genswitch.
505 mygenswitch(int num, TWORD type, struct swents **p, int n)
507 return 0;
511 /* setup call stack with a structure */
512 /* called from moveargs() */
513 static NODE *
514 movearg_struct(NODE *p, NODE *parent, int *regp)
516 int reg = *regp;
517 NODE *l, *q, *t, *r;
518 int tmpnr;
519 int navail;
520 int off;
521 int num;
522 int sz;
523 int ty;
524 int i;
526 navail = nargregs - (reg - A0);
527 sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
528 num = sz > navail ? navail : sz;
530 l = p->n_left;
531 nfree(p);
532 ty = l->n_type;
533 t = tempnode(0, l->n_type, l->n_df, l->n_ap);
534 tmpnr = regno(t);
535 l = buildtree(ASSIGN, t, l);
537 if (p != parent) {
538 q = parent->n_left;
539 } else
540 q = NULL;
542 /* copy structure into registers */
543 for (i = 0; i < num; i++) {
544 t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
545 t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
546 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
547 t = buildtree(UMUL, t, NIL);
549 r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
550 r->n_rval = reg++;
552 r = buildtree(ASSIGN, r, t);
553 if (q == NULL)
554 q = r;
555 else
556 q = block(CM, q, r, INT, 0, MKAP(INT));
558 off = ARGINIT/SZINT + nargregs;
559 for (i = num; i < sz; i++) {
560 t = tempnode(tmpnr, ty, 0, MKAP(PTR+ty));
561 t = block(SCONV, t, NIL, PTR+INT, 0, MKAP(PTR+INT));
562 t = block(PLUS, t, bcon(4*i), PTR+INT, 0, MKAP(PTR+INT));
563 t = buildtree(UMUL, t, NIL);
565 r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
566 r->n_rval = FP;
567 r = block(PLUS, r, bcon(4*off++), INT, 0, MKAP(INT));
568 r = block(UMUL, r, NIL, INT, 0, MKAP(INT));
570 r = buildtree(ASSIGN, r, t);
571 if (q == NULL)
572 q = r;
573 else
574 q = block(CM, q, r, INT, 0, MKAP(INT));
577 if (parent->n_op == CM) {
578 parent->n_left = q;
579 q = l;
580 } else {
581 q = block(CM, q, l, INT, 0, MKAP(INT));
584 *regp = reg;
585 return q;
588 /* setup call stack with 64-bit argument */
589 /* called from moveargs() */
590 static NODE *
591 movearg_64bit(NODE *p, int *regp)
593 int reg = *regp;
594 NODE *q;
595 int lastarg;
597 /* alignment */
598 ++reg;
599 reg &= ~1;
601 lastarg = A0 + nargregs - 1;
602 if (reg > lastarg) {
603 *regp = reg;
604 return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap);
607 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
608 q->n_rval = A0A1 + (reg - A0);
609 q = buildtree(ASSIGN, q, p);
611 *regp = reg + 2;
612 return q;
615 /* setup call stack with 32-bit argument */
616 /* called from moveargs() */
617 static NODE *
618 movearg_32bit(NODE *p, int *regp)
620 int reg = *regp;
621 NODE *q;
623 q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap);
624 q->n_rval = reg++;
625 q = buildtree(ASSIGN, q, p);
627 *regp = reg;
628 return q;
631 static NODE *
632 moveargs(NODE *p, int *regp)
634 NODE *r, **rp;
635 int lastreg;
636 int reg;
638 if (p->n_op == CM) {
639 p->n_left = moveargs(p->n_left, regp);
640 r = p->n_right;
641 rp = &p->n_right;
642 } else {
643 r = p;
644 rp = &p;
647 lastreg = A0 + nargregs - 1;
648 reg = *regp;
650 if (reg > lastreg && r->n_op != STARG)
651 *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap);
652 else if (r->n_op == STARG) {
653 *rp = movearg_struct(r, p, regp);
654 } else if (DEUNSIGN(r->n_type) == LONGLONG) {
655 *rp = movearg_64bit(r, regp);
656 } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) {
657 /* XXX bounce in and out of temporary to change to longlong */
658 NODE *t1 = tempnode(0, LONGLONG, 0, MKAP(LONGLONG));
659 int tmpnr = regno(t1);
660 NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
661 t1 = movearg_64bit(t1, regp);
662 r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
663 if (p->n_op == CM) {
664 p->n_left = buildtree(CM, p->n_left, t1);
665 p->n_right = r;
666 } else {
667 p = buildtree(CM, t1, r);
669 } else if (r->n_type == FLOAT) {
670 /* XXX bounce in and out of temporary to change to int */
671 NODE *t1 = tempnode(0, INT, 0, MKAP(INT));
672 int tmpnr = regno(t1);
673 NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap);
674 t1 = movearg_32bit(t1, regp);
675 r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap);
676 if (p->n_op == CM) {
677 p->n_left = buildtree(CM, p->n_left, t1);
678 p->n_right = r;
679 } else {
680 p = buildtree(CM, t1, r);
682 } else {
683 *rp = movearg_32bit(r, regp);
686 return p;
690 * Called with a function call with arguments as argument.
691 * This is done early in buildtree() and only done once.
693 NODE *
694 funcode(NODE *p)
696 int regnum = A0;
697 NODE *l, *r, *t, *q;
698 int ty;
700 l = p->n_left;
701 r = p->n_right;
704 * if returning a structure, make the first argument
705 * a hidden pointer to return structure.
707 ty = DECREF(l->n_type);
708 if (ty == STRTY+FTN || ty == UNIONTY+FTN) {
709 ty = DECREF(l->n_type) - FTN;
710 q = tempnode(0, ty, l->n_df, l->n_ap);
711 q = buildtree(ADDROF, q, NIL);
712 if (r->n_op != CM) {
713 p->n_right = block(CM, q, r, INCREF(ty),
714 l->n_df, l->n_ap);
715 } else {
716 for (t = r; t->n_left->n_op == CM; t = t->n_left)
718 t->n_left = block(CM, q, t->n_left, INCREF(ty),
719 l->n_df, l->n_ap);
723 p->n_right = moveargs(p->n_right, &regnum);
725 return p;