1 /* $Id: code.c,v 1.21 2009/02/08 16:07:52 ragge Exp $ */
3 * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 * Define everything needed to print out some data (or text).
44 * This means segment, alignment, visibility, etc.
47 defloc(struct symtab
*sp
)
49 extern char *nextsect
;
50 static char *loctbl
[] = { "text", "data", "section .rodata" };
60 s
= ISFTN(t
) ? PROG
: ISCON(cqual(t
, sp
->squal
)) ? PROG
: DATA
;
62 printf("\t.section %s\n", nextsect
);
65 } else if (s
!= lastloc
)
66 printf("\t.%s\n", loctbl
[s
]);
71 printf("\t.align %d\n", t
> USHORT
? 4 : 2);
72 n
= sp
->soname
? sp
->soname
: exname(sp
->sname
);
75 printf("\t.type %s,%%function\n", n
);
77 if (sp
->sclass
== EXTDEF
)
78 printf("\t.global %s\n", n
);
84 printf(LABFMT
":\n", sp
->soffset
);
87 /* Put a symbol in a temporary
88 * used by bfcode() and its helpers
91 putintemp(struct symtab
*sym
)
95 p
= tempnode(0, sym
->stype
, sym
->sdf
, sym
->ssue
);
96 p
= buildtree(ASSIGN
, p
, nametree(sym
));
97 sym
->soffset
= regno(p
->n_left
);
98 sym
->sflags
|= STNODE
;
102 /* setup a 64-bit parameter (double/ldouble/longlong)
103 * used by bfcode() */
105 param_64bit(struct symtab
*sym
, int *argofsp
, int dotemps
)
107 int argofs
= *argofsp
;
118 navail
= NARGREGS
- argofs
;
121 /* half in and half out of the registers */
122 if (features(FEATURE_BIGENDIAN
)) {
123 cerror("param_64bit");
126 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
127 regno(q
) = R0
+ argofs
;
129 q
= block(SCONV
, q
, NIL
,
130 ULONGLONG
, 0, MKSUE(ULONGLONG
));
132 p
->n_type
= ULONGLONG
;
134 p
->n_sue
= MKSUE(ULONGLONG
);
135 p
= block(LS
, p
, bcon(32), ULONGLONG
,
136 0, MKSUE(ULONGLONG
));
137 q
= block(PLUS
, p
, q
, ULONGLONG
,
138 0, MKSUE(ULONGLONG
));
139 p
= tempnode(0, ULONGLONG
,
140 0, MKSUE(ULONGLONG
));
141 sym
->soffset
= regno(p
);
142 sym
->sflags
|= STNODE
;
145 regno(p
) = sym
->soffset
;
148 p
->n_sue
= MKSUE(INT
);
151 p
= buildtree(ASSIGN
, p
, q
);
153 *argofsp
= argofs
+ 2;
157 q
= block(REG
, NIL
, NIL
, sym
->stype
, sym
->sdf
, sym
->ssue
);
158 regno(q
) = R0R1
+ argofs
;
160 p
= tempnode(0, sym
->stype
, sym
->sdf
, sym
->ssue
);
161 sym
->soffset
= regno(p
);
162 sym
->sflags
|= STNODE
;
166 p
= buildtree(ASSIGN
, p
, q
);
168 *argofsp
= argofs
+ 2;
171 /* setup a 32-bit param on the stack
172 * used by bfcode() */
174 param_32bit(struct symtab
*sym
, int *argofsp
, int dotemps
)
178 q
= block(REG
, NIL
, NIL
, sym
->stype
, sym
->sdf
, sym
->ssue
);
179 regno(q
) = R0
+ (*argofsp
)++;
181 p
= tempnode(0, sym
->stype
, sym
->sdf
, sym
->ssue
);
182 sym
->soffset
= regno(p
);
183 sym
->sflags
|= STNODE
;
187 p
= buildtree(ASSIGN
, p
, q
);
191 /* setup a double param on the stack
192 * used by bfcode() */
194 param_double(struct symtab
*sym
, int *argofsp
, int dotemps
)
200 * we have to dump the float from the general register
201 * into a temp, since the register allocator doesn't like
202 * floats to be in CLASSA. This may not work for -xtemps.
205 t
= tempnode(0, ULONGLONG
, 0, MKSUE(ULONGLONG
));
207 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
208 q
->n_rval
= R0R1
+ (*argofsp
)++;
209 p
= buildtree(ASSIGN
, t
, q
);
213 sym
->soffset
= tmpnr
;
214 sym
->sflags
|= STNODE
;
216 q
= tempnode(tmpnr
, sym
->stype
, sym
->sdf
, sym
->ssue
);
218 p
= buildtree(ASSIGN
, p
, q
);
223 /* setup a float param on the stack
224 * used by bfcode() */
226 param_float(struct symtab
*sym
, int *argofsp
, int dotemps
)
232 * we have to dump the float from the general register
233 * into a temp, since the register allocator doesn't like
234 * floats to be in CLASSA. This may not work for -xtemps.
237 t
= tempnode(0, INT
, 0, MKSUE(INT
));
239 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
240 q
->n_rval
= R0
+ (*argofsp
)++;
241 p
= buildtree(ASSIGN
, t
, q
);
245 sym
->soffset
= tmpnr
;
246 sym
->sflags
|= STNODE
;
248 q
= tempnode(tmpnr
, sym
->stype
, sym
->sdf
, sym
->ssue
);
250 p
= buildtree(ASSIGN
, p
, q
);
255 /* setup the hidden pointer to struct return parameter
256 * used by bfcode() */
258 param_retstruct(void)
262 p
= tempnode(0, PTR
-FTN
+cftnsp
->stype
, 0, cftnsp
->ssue
);
264 q
= block(REG
, NIL
, NIL
, PTR
+STRTY
, 0, cftnsp
->ssue
);
266 p
= buildtree(ASSIGN
, p
, q
);
271 /* setup struct parameter
272 * push the registers out to memory
273 * used by bfcode() */
275 param_struct(struct symtab
*sym
, int *argofsp
)
277 int argofs
= *argofsp
;
285 navail
= NARGREGS
- argofs
;
286 sz
= tsize(sym
->stype
, sym
->sdf
, sym
->ssue
) / SZINT
;
287 off
= ARGINIT
/SZINT
+ argofs
;
288 num
= sz
> navail
? navail
: sz
;
289 for (i
= 0; i
< num
; i
++) {
290 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
291 regno(q
) = R0
+ argofs
++;
292 p
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
294 p
= block(PLUS
, p
, bcon(4*off
++), INT
, 0, MKSUE(INT
));
295 p
= block(UMUL
, p
, NIL
, INT
, 0, MKSUE(INT
));
296 p
= buildtree(ASSIGN
, p
, q
);
305 * Beginning-of-function code:
307 * 'sp' is an array of indices in symtab for the arguments
308 * 'cnt' is the number of arguments
311 bfcode(struct symtab
**sp
, int cnt
)
318 * Detect if this function has ellipses and save all
319 * argument registers onto stack.
321 usym
= cftnsp
->sdf
->dfun
;
322 while (usym
&& usym
->type
!= TNULL
) {
323 if (usym
->type
== TELLIPSIS
) {
330 /* if returning a structure, move the hidden argument into a TEMP */
331 if (cftnsp
->stype
== STRTY
+FTN
|| cftnsp
->stype
== UNIONTY
+FTN
) {
336 /* recalculate the arg offset and create TEMP moves */
337 for (i
= 0; i
< cnt
; i
++) {
342 if ((argofs
>= NARGREGS
) && !xtemps
)
345 if (argofs
> NARGREGS
) {
347 } else if (sp
[i
]->stype
== STRTY
|| sp
[i
]->stype
== UNIONTY
) {
348 param_struct(sp
[i
], &argofs
);
349 } else if (DEUNSIGN(sp
[i
]->stype
) == LONGLONG
) {
350 param_64bit(sp
[i
], &argofs
, xtemps
&& !saveallargs
);
351 } else if (sp
[i
]->stype
== DOUBLE
|| sp
[i
]->stype
== LDOUBLE
) {
352 if (features(FEATURE_HARDFLOAT
))
353 param_double(sp
[i
], &argofs
,
354 xtemps
&& !saveallargs
);
356 param_64bit(sp
[i
], &argofs
,
357 xtemps
&& !saveallargs
);
358 } else if (sp
[i
]->stype
== FLOAT
) {
359 if (features(FEATURE_HARDFLOAT
))
360 param_float(sp
[i
], &argofs
,
361 xtemps
&& !saveallargs
);
363 param_32bit(sp
[i
], &argofs
,
364 xtemps
&& !saveallargs
);
366 param_32bit(sp
[i
], &argofs
, xtemps
&& !saveallargs
);
370 /* if saveallargs, save the rest of the args onto the stack */
371 while (saveallargs
&& argofs
< NARGREGS
) {
373 int off
= ARGINIT
/SZINT
+ argofs
;
374 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
375 regno(q
) = R0
+ argofs
++;
376 p
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
378 p
= block(PLUS
, p
, bcon(4*off
), INT
, 0, MKSUE(INT
));
379 p
= block(UMUL
, p
, NIL
, INT
, 0, MKSUE(INT
));
380 p
= buildtree(ASSIGN
, p
, q
);
387 * End-of-Function code:
395 if (cftnsp
->stype
!= STRTY
+FTN
&& cftnsp
->stype
!= UNIONTY
+FTN
)
399 * At this point, the address of the return structure on
400 * has been FORCEd to RETREG, which is R0.
401 * We want to copy the contents from there to the address
402 * we placed into the tempnode "rvnr".
405 /* move the pointer out of R0 to a tempnode */
406 q
= block(REG
, NIL
, NIL
, PTR
+STRTY
, 0, cftnsp
->ssue
);
408 p
= tempnode(0, PTR
+STRTY
, 0, cftnsp
->ssue
);
410 p
= buildtree(ASSIGN
, p
, q
);
413 /* get the address from the tempnode */
414 q
= tempnode(tempnr
, PTR
+STRTY
, 0, cftnsp
->ssue
);
415 q
= buildtree(UMUL
, q
, NIL
);
417 /* now, get the structure destination */
418 p
= tempnode(rvnr
, PTR
+STRTY
, 0, cftnsp
->ssue
);
419 p
= buildtree(UMUL
, p
, NIL
);
421 /* struct assignment */
422 p
= buildtree(ASSIGN
, p
, q
);
427 * Beginning-of-code: finished generating function prologue
429 * by now, the automatics and register variables are allocated
434 SETOFF(autooff
, SZINT
);
438 * End-of-job: called just before final exit.
444 #define MKSTR(x) _MKSTR(x)
445 #define OS MKSTR(TARGOS)
446 printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING
, OS
);
450 * Beginning-of-job: called before compilation starts
452 * Initialise data structures specific for the local machine.
460 * Compute the alignment of object with type 't'.
463 fldal(unsigned int t
)
465 uerror("illegal field type");
470 * fix up type of field p
473 fldty(struct symtab
*p
)
478 * Build target-dependent switch tree/table.
480 * Return 1 if successfull, otherwise return 0 and the
481 * target-independent tree will be used.
484 mygenswitch(int num
, TWORD type
, struct swents
**p
, int n
)
491 * Straighten a chain of CM ops so that the CM nodes
492 * only appear on the left node.
502 NODE
*r
= p
->n_right
;
504 if (p
->n_op
!= CM
|| r
->n_op
!= CM
)
507 p
->n_right
= r
->n_left
;
514 reverse1(NODE
*p
, NODE
*a
)
517 NODE
*r
= p
->n_right
;
523 return reverse1(l
, p
);
531 * Reverse a chain of CM ops
537 NODE
*r
= p
->n_right
;
542 return reverse1(l
, p
);
550 /* push arg onto the stack */
551 /* called by moveargs() */
553 pusharg(NODE
*p
, int *regp
)
558 /* convert to register size, if smaller */
559 sz
= tsize(p
->n_type
, p
->n_df
, p
->n_sue
);
561 p
= block(SCONV
, p
, NIL
, INT
, 0, MKSUE(INT
));
563 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
566 if (szty(p
->n_type
) == 1) {
568 q
= block(MINUSEQ
, q
, bcon(4), INT
, 0, MKSUE(INT
));
571 q
= block(MINUSEQ
, q
, bcon(8), INT
, 0, MKSUE(INT
));
574 q
= block(UMUL
, q
, NIL
, p
->n_type
, p
->n_df
, p
->n_sue
);
576 return buildtree(ASSIGN
, q
, p
);
579 /* setup call stack with 32-bit argument */
580 /* called from moveargs() */
582 movearg_32bit(NODE
*p
, int *regp
)
587 q
= block(REG
, NIL
, NIL
, p
->n_type
, p
->n_df
, p
->n_sue
);
589 q
= buildtree(ASSIGN
, q
, p
);
595 /* setup call stack with 64-bit argument */
596 /* called from moveargs() */
598 movearg_64bit(NODE
*p
, int *regp
)
611 q
= pusharg(p
, regp
);
612 } else if (reg
== R3
) {
613 /* half in and half out of the registers */
615 if (!features(FEATURE_BIGENDIAN
)) {
616 q
= block(SCONV
, p
, NIL
, INT
, 0, MKSUE(INT
));
617 q
= movearg_32bit(q
, regp
); /* little-endian */
618 r
= buildtree(RS
, r
, bcon(32));
619 r
= block(SCONV
, r
, NIL
, INT
, 0, MKSUE(INT
));
620 r
= pusharg(r
, regp
); /* little-endian */
622 q
= buildtree(RS
, p
, bcon(32));
623 q
= block(SCONV
, q
, NIL
, INT
, 0, MKSUE(INT
));
624 q
= movearg_32bit(q
, regp
); /* big-endian */
625 r
= block(SCONV
, r
, NIL
, INT
, 0, MKSUE(INT
));
626 r
= pusharg(r
, regp
); /* big-endian */
628 q
= straighten(block(CM
, q
, r
, p
->n_type
, p
->n_df
, p
->n_sue
));
630 q
= block(REG
, NIL
, NIL
, p
->n_type
, p
->n_df
, p
->n_sue
);
631 regno(q
) = R0R1
+ (reg
- R0
);
632 q
= buildtree(ASSIGN
, q
, p
);
639 /* setup call stack with float/double argument */
640 /* called from moveargs() */
642 movearg_float(NODE
*p
, int *regp
)
645 TWORD ty
= INCREF(p
->n_type
);
649 * Floats are passed in the general registers for
650 * compatibily with libraries compiled to handle soft-float.
655 r
= block(REG
, NIL
, NIL
, ty
, p
->n_df
, p
->n_sue
);
657 r
= block(PLUS
, r
, bcon(-4), ty
, p
->n_df
, p
->n_sue
);
658 r
= block(UMUL
, r
, NIL
, p
->n_type
, p
->n_df
, p
->n_sue
);
659 r
= buildtree(ASSIGN
, r
, p
);
662 /* bounce into temp */
663 r
= block(REG
, NIL
, NIL
, PTR
+INT
, 0, MKSUE(INT
));
665 r
= block(PLUS
, r
, bcon(-8), PTR
+INT
, 0, MKSUE(INT
));
666 r
= block(UMUL
, r
, NIL
, INT
, 0, MKSUE(INT
));
667 q
= tempnode(0, INT
, 0, MKSUE(INT
));
669 r
= buildtree(ASSIGN
, q
, r
);
672 /* copy directly into temp */
673 q
= tempnode(0, p
->n_type
, p
->n_df
, p
->n_sue
);
675 r
= buildtree(ASSIGN
, q
, p
);
679 /* copy from temp to register parameter */
680 r
= tempnode(tmpnr
, INT
, 0, MKSUE(INT
));
681 q
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
682 regno(q
) = (*regp
)++;
683 p
= buildtree(ASSIGN
, q
, r
);
688 /* setup call stack with float/double argument */
689 /* called from moveargs() */
691 movearg_double(NODE
*p
, int *regp
)
694 TWORD ty
= INCREF(p
->n_type
);
699 r
= block(REG
, NIL
, NIL
, ty
, p
->n_df
, p
->n_sue
);
701 r
= block(PLUS
, r
, bcon(-8), ty
, p
->n_df
, p
->n_sue
);
702 r
= block(UMUL
, r
, NIL
, p
->n_type
, p
->n_df
, p
->n_sue
);
703 r
= buildtree(ASSIGN
, r
, p
);
706 /* bounce into temp */
707 r
= block(REG
, NIL
, NIL
, PTR
+LONGLONG
, 0, MKSUE(LONGLONG
));
709 r
= block(PLUS
, r
, bcon(-8), PTR
+LONGLONG
, 0, MKSUE(LONGLONG
));
710 r
= block(UMUL
, r
, NIL
, LONGLONG
, 0, MKSUE(LONGLONG
));
711 q
= tempnode(0, LONGLONG
, 0, MKSUE(LONGLONG
));
713 r
= buildtree(ASSIGN
, q
, r
);
716 /* copy directly into temp */
717 q
= tempnode(0, p
->n_type
, p
->n_df
, p
->n_sue
);
719 r
= buildtree(ASSIGN
, q
, p
);
723 /* copy from temp to register parameter */
724 r
= tempnode(tmpnr
, LONGLONG
, 0, MKSUE(LONGLONG
));
725 q
= block(REG
, NIL
, NIL
, LONGLONG
, 0, MKSUE(LONGLONG
));
726 regno(q
) = R0R1
- R0
+ (*regp
);
727 p
= buildtree(ASSIGN
, q
, r
);
735 /* setup call stack with a structure */
736 /* called from moveargs() */
738 movearg_struct(NODE
*p
, int *regp
)
749 assert(p
->n_op
== STARG
);
751 navail
= NARGREGS
- (reg
- R0
);
752 navail
= navail
< 0 ? 0 : navail
;
753 sz
= tsize(p
->n_type
, p
->n_df
, p
->n_sue
) / SZINT
;
754 num
= sz
> navail
? navail
: sz
;
756 /* remove STARG node */
762 * put it into a TEMP, rather than tcopy(), since the tree
763 * in p may have side-affects
765 t
= tempnode(0, ty
, l
->n_df
, l
->n_sue
);
767 q
= buildtree(ASSIGN
, t
, l
);
769 /* copy structure into registers */
770 for (i
= 0; i
< num
; i
++) {
771 t
= tempnode(tmpnr
, ty
, 0, MKSUE(PTR
+ty
));
772 t
= block(SCONV
, t
, NIL
, PTR
+INT
, 0, MKSUE(PTR
+INT
));
773 t
= block(PLUS
, t
, bcon(4*i
), PTR
+INT
, 0, MKSUE(PTR
+INT
));
774 t
= buildtree(UMUL
, t
, NIL
);
776 r
= block(REG
, NIL
, NIL
, INT
, 0, MKSUE(INT
));
778 r
= buildtree(ASSIGN
, r
, t
);
780 q
= block(CM
, q
, r
, INT
, 0, MKSUE(INT
));
783 /* put the rest of the structure on the stack */
784 for (i
= num
; i
< sz
; i
++) {
785 t
= tempnode(tmpnr
, ty
, 0, MKSUE(PTR
+ty
));
786 t
= block(SCONV
, t
, NIL
, PTR
+INT
, 0, MKSUE(PTR
+INT
));
787 t
= block(PLUS
, t
, bcon(4*i
), PTR
+INT
, 0, MKSUE(PTR
+INT
));
788 t
= buildtree(UMUL
, t
, NIL
);
789 r
= pusharg(t
, ®
);
790 q
= block(CM
, q
, r
, INT
, 0, MKSUE(INT
));
801 moveargs(NODE
*p
, int *regp
)
807 p
->n_left
= moveargs(p
->n_left
, regp
);
817 if (reg
> R3
&& r
->n_op
!= STARG
) {
818 *rp
= pusharg(r
, regp
);
819 } else if (r
->n_op
== STARG
) {
820 *rp
= movearg_struct(r
, regp
);
821 } else if (DEUNSIGN(r
->n_type
) == LONGLONG
) {
822 *rp
= movearg_64bit(r
, regp
);
823 } else if (r
->n_type
== DOUBLE
|| r
->n_type
== LDOUBLE
) {
824 *rp
= movearg_double(r
, regp
);
825 } else if (r
->n_type
== FLOAT
) {
826 *rp
= movearg_float(r
, regp
);
828 *rp
= movearg_32bit(r
, regp
);
831 return straighten(p
);
835 * Fixup arguments to pass pointer-to-struct as first argument.
837 * called from funcode().
848 ty
= DECREF(l
->n_type
) - FTN
;
850 // assert(tsize(ty, l->n_df, l->n_sue) == SZINT);
852 /* structure assign */
853 q
= tempnode(0, ty
, l
->n_df
, l
->n_sue
);
854 q
= buildtree(ADDROF
, q
, NIL
);
856 /* insert hidden assignment at beginning of list */
858 p
->n_right
= block(CM
, q
, r
, INCREF(ty
), l
->n_df
, l
->n_sue
);
860 for (t
= r
; t
->n_left
->n_op
== CM
; t
= t
->n_left
)
862 t
->n_left
= block(CM
, q
, t
->n_left
, INCREF(ty
),
870 * Called with a function call with arguments as argument.
871 * This is done early in buildtree() and only done once.
878 if (p
->n_type
== STRTY
+FTN
|| p
->n_type
== UNIONTY
+FTN
) {
883 p
->n_right
= moveargs(p
->n_right
, ®
);
885 if (p
->n_right
== NULL
)
886 p
->n_op
+= (UCALL
- CALL
);