1 /* $Id: code.c,v 1.17 2010/09/19 14:01:35 ragge Exp $ */
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
39 * Define everything needed to print out some data (or text).
40 * This means segment, alignment, visibility, etc.
43 defloc(struct symtab
*sp
)
45 static char *loctbl
[] = { "text", "data", "section .rodata" };
46 static int lastloc
= -1;
56 s
= ISFTN(t
) ? PROG
: ISCON(cqual(t
, sp
->squal
)) ? RDATA
: DATA
;
59 return; /* text is written in prologue() */
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) {
68 printf("\t.type %s,@object\n", n
);
69 printf("\t.size %s," CONFMT
"\n", n
,
70 tsize(sp
->stype
, sp
->sdf
, sp
->sap
));
74 printf(LABFMT
":\n", sp
->soffset
);
80 * cause the alignment to become a multiple of n
81 * never called for text segment.
86 n
= ispow2(n
/ SZCHAR
);
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.
97 defnam(struct symtab
*p
)
101 if (p
->sclass
== EXTDEF
)
102 printf("\t.globl %s\n", c
);
104 printf("\t.type %s,@object\n", c
);
105 printf("\t.size %s," CONFMT
"\n", c
, tsize(p
->stype
, p
->sdf
, p
->sap
));
114 * code for the end of a function
115 * deals with struct return here
124 if (cftnsp
->stype
!= STRTY
+FTN
&& cftnsp
->stype
!= UNIONTY
+FTN
)
127 ty
= cftnsp
->stype
- FTN
;
129 q
= block(REG
, NIL
, NIL
, INCREF(ty
), 0, cftnsp
->sap
);
131 p
= tempnode(0, INCREF(ty
), 0, cftnsp
->sap
);
133 p
= buildtree(ASSIGN
, p
, q
);
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
);
145 q
= tempnode(rvnr
, INCREF(ty
), 0, cftnsp
->sap
);
146 p
= block(REG
, NIL
, NIL
, INCREF(ty
), 0, cftnsp
->sap
);
148 p
= buildtree(ASSIGN
, p
, q
);
152 /* Put a symbol in a temporary
153 * used by bfcode() and its helpers */
155 putintemp(struct symtab
*sym
)
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
;
165 /* setup the hidden pointer to struct return parameter
166 * used by bfcode() */
172 p
= tempnode(0, PTR
+STRTY
, 0, cftnsp
->sap
);
174 q
= block(REG
, NIL
, NIL
, PTR
+STRTY
, 0, cftnsp
->sap
);
176 p
= buildtree(ASSIGN
, p
, q
);
180 /* setup struct parameter
181 * push the registers out to memory
182 * used by bfcode() */
184 param_struct(struct symtab
*sym
, int *regp
)
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
));
201 p
= block(REG
, NIL
, NIL
, INT
, 0, MKAP(INT
));
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
);
212 /* setup a 64-bit parameter (double/ldouble/longlong)
213 * used by bfcode() */
215 param_64bit(struct symtab
*sym
, int *regp
, int dotemps
)
225 navail
= nargregs
- (reg
- A0
);
228 /* would have appeared half in registers/half
229 * on the stack, but alignment ensures it
230 * appears on the stack */
237 q
= block(REG
, NIL
, NIL
, sym
->stype
, sym
->sdf
, sym
->sap
);
238 q
->n_rval
= A0A1
+ (reg
- A0
);
240 p
= tempnode(0, sym
->stype
, sym
->sdf
, sym
->sap
);
241 sym
->soffset
= regno(p
);
242 sym
->sflags
|= STNODE
;
246 p
= buildtree(ASSIGN
, p
, q
);
251 /* setup a 32-bit param on the stack
252 * used by bfcode() */
254 param_32bit(struct symtab
*sym
, int *regp
, int dotemps
)
258 q
= block(REG
, NIL
, NIL
, sym
->stype
, sym
->sdf
, sym
->sap
);
259 q
->n_rval
= (*regp
)++;
261 p
= tempnode(0, sym
->stype
, sym
->sdf
, sym
->sap
);
262 sym
->soffset
= regno(p
);
263 sym
->sflags
|= STNODE
;
267 p
= buildtree(ASSIGN
, p
, q
);
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.
277 param_double(struct symtab
*sym
, int *regp
, int dotemps
)
288 navail
= nargregs
- (reg
- A0
);
291 /* would have appeared half in registers/half
292 * on the stack, but alignment ensures it
293 * appears on the stack */
300 t
= tempnode(0, LONGLONG
, 0, MKAP(LONGLONG
));
302 q
= block(REG
, NIL
, NIL
, LONGLONG
, 0, MKAP(LONGLONG
));
303 q
->n_rval
= A0A1
+ (reg
- A0
);
304 p
= buildtree(ASSIGN
, t
, q
);
308 sym
->soffset
= tmpnr
;
309 sym
->sflags
|= STNODE
;
311 q
= tempnode(tmpnr
, sym
->stype
, sym
->sdf
, sym
->sap
);
313 p
= buildtree(ASSIGN
, p
, q
);
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.
325 param_float(struct symtab
*sym
, int *regp
, int dotemps
)
330 t
= tempnode(0, INT
, 0, MKAP(INT
));
332 q
= block(REG
, NIL
, NIL
, INT
, 0, MKAP(INT
));
333 q
->n_rval
= (*regp
)++;
334 p
= buildtree(ASSIGN
, t
, q
);
338 sym
->soffset
= tmpnr
;
339 sym
->sflags
|= STNODE
;
341 q
= tempnode(tmpnr
, sym
->stype
, sym
->sdf
, sym
->sap
);
343 p
= buildtree(ASSIGN
, p
, q
);
349 * code for the beginning of a function; a is an array of
350 * indices in symtab for the arguments; n is the number
353 bfcode(struct symtab
**sp
, int cnt
)
356 int lastreg
= A0
+ nargregs
- 1;
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
) {
375 /* assign hidden return structure to temporary */
376 if (cftnsp
->stype
== STRTY
+FTN
|| cftnsp
->stype
== UNIONTY
+FTN
) {
381 /* recalculate the arg offset and create TEMP moves */
382 for (i
= 0; i
< cnt
; i
++) {
384 if ((reg
> lastreg
) && !xtemps
)
386 else if (reg
> lastreg
)
388 else if (sp
[i
]->stype
== STRTY
|| sp
[i
]->stype
== UNIONTY
)
389 param_struct(sp
[i
], ®
);
390 else if (DEUNSIGN(sp
[i
]->stype
) == LONGLONG
)
391 param_64bit(sp
[i
], ®
, xtemps
&& !saveallargs
);
392 else if (sp
[i
]->stype
== DOUBLE
|| sp
[i
]->stype
== LDOUBLE
)
393 param_double(sp
[i
], ®
, xtemps
&& !saveallargs
);
394 else if (sp
[i
]->stype
== FLOAT
)
395 param_float(sp
[i
], ®
, xtemps
&& !saveallargs
);
397 param_32bit(sp
[i
], ®
, xtemps
&& !saveallargs
);
400 /* if saveallargs, save the rest of the args onto the stack */
403 while (reg
<= lastreg
) {
405 int off
= ARGINIT
/SZINT
+ (reg
- A0
);
406 q
= block(REG
, NIL
, NIL
, INT
, 0, MKAP(INT
));
408 p
= block(REG
, NIL
, NIL
, INT
, 0, MKAP(INT
));
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
);
420 * by now, the automatics and register variables are allocated
425 SETOFF(autooff
, SZINT
);
428 /* called just before final exit */
429 /* flag is 1 if errors, 0 if none */
438 printf("\t.section .mdebug.abi32\n");
439 printf("\t.previous\n");
440 printf("\t.abicalls\n");
445 * Print character t at position i in one string, until t == -1.
446 * Locctr & label is already defined.
451 static int lastoctal
= 0;
453 /* put byte i+1 in a string */
460 printf("\t.ascii \"");
463 else if (t
== '\\' || t
== '"') {
467 } else if (t
== 011) {
469 } else if (t
== 012) {
471 } else if (t
< 040 || t
>= 0177) {
474 } else if (lastoctal
&& '0' <= t
&& t
<= '9') {
476 printf("\"\n\t.ascii \"%c", t
);
486 * return the alignment of field of type t
489 fldal(unsigned int t
)
491 uerror("illegal field type");
495 /* fix up type of field p */
497 fldty(struct symtab
*p
)
502 * XXX - fix genswitch.
505 mygenswitch(int num
, TWORD type
, struct swents
**p
, int n
)
511 /* setup call stack with a structure */
512 /* called from moveargs() */
514 movearg_struct(NODE
*p
, NODE
*parent
, int *regp
)
526 navail
= nargregs
- (reg
- A0
);
527 sz
= tsize(p
->n_type
, p
->n_df
, p
->n_ap
) / SZINT
;
528 num
= sz
> navail
? navail
: sz
;
533 t
= tempnode(0, l
->n_type
, l
->n_df
, l
->n_ap
);
535 l
= buildtree(ASSIGN
, t
, l
);
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
));
552 r
= buildtree(ASSIGN
, r
, t
);
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
));
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
);
574 q
= block(CM
, q
, r
, INT
, 0, MKAP(INT
));
577 if (parent
->n_op
== CM
) {
581 q
= block(CM
, q
, l
, INT
, 0, MKAP(INT
));
588 /* setup call stack with 64-bit argument */
589 /* called from moveargs() */
591 movearg_64bit(NODE
*p
, int *regp
)
601 lastarg
= A0
+ nargregs
- 1;
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
);
615 /* setup call stack with 32-bit argument */
616 /* called from moveargs() */
618 movearg_32bit(NODE
*p
, int *regp
)
623 q
= block(REG
, NIL
, NIL
, p
->n_type
, p
->n_df
, p
->n_ap
);
625 q
= buildtree(ASSIGN
, q
, p
);
632 moveargs(NODE
*p
, int *regp
)
639 p
->n_left
= moveargs(p
->n_left
, regp
);
647 lastreg
= A0
+ nargregs
- 1;
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
);
664 p
->n_left
= buildtree(CM
, p
->n_left
, t1
);
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
);
677 p
->n_left
= buildtree(CM
, p
->n_left
, t1
);
680 p
= buildtree(CM
, t1
, r
);
683 *rp
= movearg_32bit(r
, regp
);
690 * Called with a function call with arguments as argument.
691 * This is done early in buildtree() and only done once.
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
);
713 p
->n_right
= block(CM
, q
, r
, INCREF(ty
),
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
),
723 p
->n_right
= moveargs(p
->n_right
, ®num
);