source: mainline/uspace/app/pcc/arch/mips/code.c@ 423e5e87

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 423e5e87 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 15.8 KB
Line 
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.
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
30/*
31 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
32 * Simon Olsson (simols-1@student.ltu.se) 2005.
33 */
34
35#include <assert.h>
36#include "pass1.h"
37
38/*
39 * Define everything needed to print out some data (or text).
40 * This means segment, alignment, visibility, etc.
41 */
42void
43defloc(struct symtab *sp)
44{
45 static char *loctbl[] = { "text", "data", "section .rodata" };
46 static int lastloc = -1;
47 TWORD t;
48 char *n;
49 int s;
50
51 if (sp == NULL) {
52 lastloc = -1;
53 return;
54 }
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);
75}
76
77
78#ifdef notdef
79/*
80 * cause the alignment to become a multiple of n
81 * never called for text segment.
82 */
83void
84defalign(int n)
85{
86 n = ispow2(n / SZCHAR);
87 if (n == -1)
88 cerror("defalign: n != 2^i");
89 printf("\t.p2align %d\n", n);
90}
91
92/*
93 * define the current location as the name p->sname
94 * never called for text segment.
95 */
96void
97defnam(struct symtab *p)
98{
99 char *c = p->soname;
100
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);
108}
109#endif
110
111static int rvnr;
112
113/*
114 * code for the end of a function
115 * deals with struct return here
116 */
117void
118efcode()
119{
120 NODE *p, *q;
121 int tempnr;
122 int ty;
123
124 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
125 return;
126
127 ty = cftnsp->stype - FTN;
128
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);
135
136 q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap);
137 q = buildtree(UMUL, q, NIL);
138
139 p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap);
140 p = buildtree(UMUL, p, NIL);
141
142 p = buildtree(ASSIGN, p, q);
143 ecomp(p);
144
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);
150}
151
152/* Put a symbol in a temporary
153 * used by bfcode() and its helpers */
154static void
155putintemp(struct symtab *sym)
156{
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);
163}
164
165/* setup the hidden pointer to struct return parameter
166 * used by bfcode() */
167static void
168param_retptr(void)
169{
170 NODE *p, *q;
171
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);
178}
179
180/* setup struct parameter
181 * push the registers out to memory
182 * used by bfcode() */
183static void
184param_struct(struct symtab *sym, int *regp)
185{
186 int reg = *regp;
187 NODE *p, *q;
188 int navail;
189 int sz;
190 int off;
191 int num;
192 int i;
193
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);
207 }
208
209 *regp = reg;
210}
211
212/* setup a 64-bit parameter (double/ldouble/longlong)
213 * used by bfcode() */
214static void
215param_64bit(struct symtab *sym, int *regp, int dotemps)
216{
217 int reg = *regp;
218 NODE *p, *q;
219 int navail;
220
221 /* alignment */
222 ++reg;
223 reg &= ~1;
224
225 navail = nargregs - (reg - A0);
226
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;
235 }
236
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);
245 }
246 p = buildtree(ASSIGN, p, q);
247 ecomp(p);
248 *regp = reg + 2;
249}
250
251/* setup a 32-bit param on the stack
252 * used by bfcode() */
253static void
254param_32bit(struct symtab *sym, int *regp, int dotemps)
255{
256 NODE *p, *q;
257
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);
266 }
267 p = buildtree(ASSIGN, p, q);
268 ecomp(p);
269}
270
271/*
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.
275 */
276static void
277param_double(struct symtab *sym, int *regp, int dotemps)
278{
279 int reg = *regp;
280 NODE *p, *q, *t;
281 int navail;
282 int tmpnr;
283
284 /* alignment */
285 ++reg;
286 reg &= ~1;
287
288 navail = nargregs - (reg - A0);
289
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;
298 }
299
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);
306
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);
315 }
316 *regp = reg + 2;
317}
318
319/*
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.
323 */
324static void
325param_float(struct symtab *sym, int *regp, int dotemps)
326{
327 NODE *p, *q, *t;
328 int tmpnr;
329
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);
336
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);
345 }
346}
347
348/*
349 * code for the beginning of a function; a is an array of
350 * indices in symtab for the arguments; n is the number
351 */
352void
353bfcode(struct symtab **sp, int cnt)
354{
355 union arglist *usym;
356 int lastreg = A0 + nargregs - 1;
357 int saveallargs = 0;
358 int i, reg;
359
360 /*
361 * Detect if this function has ellipses and save all
362 * argument register onto stack.
363 */
364 usym = cftnsp->sdf->dfun;
365 while (usym && usym->type != TNULL) {
366 if (usym->type == TELLIPSIS) {
367 saveallargs = 1;
368 break;
369 }
370 ++usym;
371 }
372
373 reg = A0;
374
375 /* assign hidden return structure to temporary */
376 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
377 param_retptr();
378 ++reg;
379 }
380
381 /* recalculate the arg offset and create TEMP moves */
382 for (i = 0; i < cnt; i++) {
383
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);
398 }
399
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);
414 }
415
416}
417
418
419/*
420 * by now, the automatics and register variables are allocated
421 */
422void
423bccode()
424{
425 SETOFF(autooff, SZINT);
426}
427
428/* called just before final exit */
429/* flag is 1 if errors, 0 if none */
430void
431ejobcode(int flag )
432{
433}
434
435void
436bjobcode()
437{
438 printf("\t.section .mdebug.abi32\n");
439 printf("\t.previous\n");
440 printf("\t.abicalls\n");
441}
442
443#ifdef notdef
444/*
445 * Print character t at position i in one string, until t == -1.
446 * Locctr & label is already defined.
447 */
448void
449bycode(int t, int i)
450{
451 static int lastoctal = 0;
452
453 /* put byte i+1 in a string */
454
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);
480 }
481 }
482}
483#endif
484
485/*
486 * return the alignment of field of type t
487 */
488int
489fldal(unsigned int t)
490{
491 uerror("illegal field type");
492 return(ALINT);
493}
494
495/* fix up type of field p */
496void
497fldty(struct symtab *p)
498{
499}
500
501/*
502 * XXX - fix genswitch.
503 */
504int
505mygenswitch(int num, TWORD type, struct swents **p, int n)
506{
507 return 0;
508}
509
510
511/* setup call stack with a structure */
512/* called from moveargs() */
513static NODE *
514movearg_struct(NODE *p, NODE *parent, int *regp)
515{
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;
525
526 navail = nargregs - (reg - A0);
527 sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT;
528 num = sz > navail ? navail : sz;
529
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);
536
537 if (p != parent) {
538 q = parent->n_left;
539 } else
540 q = NULL;
541
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);
548
549 r = block(REG, NIL, NIL, INT, 0, MKAP(INT));
550 r->n_rval = reg++;
551
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));
557 }
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);
564
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));
569
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));
575 }
576
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));
582 }
583
584 *regp = reg;
585 return q;
586}
587
588/* setup call stack with 64-bit argument */
589/* called from moveargs() */
590static NODE *
591movearg_64bit(NODE *p, int *regp)
592{
593 int reg = *regp;
594 NODE *q;
595 int lastarg;
596
597 /* alignment */
598 ++reg;
599 reg &= ~1;
600
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);
605 }
606
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);
610
611 *regp = reg + 2;
612 return q;
613}
614
615/* setup call stack with 32-bit argument */
616/* called from moveargs() */
617static NODE *
618movearg_32bit(NODE *p, int *regp)
619{
620 int reg = *regp;
621 NODE *q;
622
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);
626
627 *regp = reg;
628 return q;
629}
630
631static NODE *
632moveargs(NODE *p, int *regp)
633{
634 NODE *r, **rp;
635 int lastreg;
636 int reg;
637
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;
645 }
646
647 lastreg = A0 + nargregs - 1;
648 reg = *regp;
649
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);
668 }
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);
681 }
682 } else {
683 *rp = movearg_32bit(r, regp);
684 }
685
686 return p;
687}
688
689/*
690 * Called with a function call with arguments as argument.
691 * This is done early in buildtree() and only done once.
692 */
693NODE *
694funcode(NODE *p)
695{
696 int regnum = A0;
697 NODE *l, *r, *t, *q;
698 int ty;
699
700 l = p->n_left;
701 r = p->n_right;
702
703 /*
704 * if returning a structure, make the first argument
705 * a hidden pointer to return structure.
706 */
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)
717 ;
718 t->n_left = block(CM, q, t->n_left, INCREF(ty),
719 l->n_df, l->n_ap);
720 }
721 }
722
723 p->n_right = moveargs(p->n_right, &regnum);
724
725 return p;
726}
Note: See TracBrowser for help on using the repository browser.