1 /* $Id: local.c,v 1.24 2011/01/21 21:47:58 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.
30 * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and
31 * Simon Olsson (simols-1@student.ltu.se) 2005.
37 #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
39 static int inbits
, inval
;
41 /* this is called to do local transformations on
42 * an expression tree preparitory to its being
43 * written out in intermediate code.
53 int tmpnr
, isptrvoid
= 0;
57 printf("clocal in: %p\n", p
);
62 switch (o
= p
->n_op
) {
68 if (p
->n_type
== VOID
)
71 * if the function returns void*, ecode() invokes
72 * delvoid() to convert it to uchar*.
73 * We just let this happen on the ASSIGN to the temp,
74 * and cast the pointer back to void* on access
77 if (p
->n_type
== PTR
+VOID
)
79 r
= tempnode(0, p
->n_type
, p
->n_df
, p
->n_ap
);
81 r
= block(ASSIGN
, r
, p
, p
->n_type
, p
->n_df
, p
->n_ap
);
83 p
= tempnode(tmpnr
, r
->n_type
, r
->n_df
, r
->n_ap
);
85 p
= block(PCONV
, p
, NIL
, PTR
+VOID
,
86 p
->n_df
, MKAP(PTR
+VOID
));
88 p
= buildtree(COMOP
, r
, p
);
92 if ((q
= p
->n_sp
) == NULL
)
93 return p
; /* Nothing to care about */
99 /* fake up a structure reference */
100 r
= block(REG
, NIL
, NIL
, PTR
+STRTY
, 0, 0);
103 p
= stref(block(STREF
, r
, p
, 0, 0, 0));
116 p
->n_rval
= q
->soffset
;
123 /* Args smaller than int are given as int */
124 if (p
->n_type
!= CHAR
&& p
->n_type
!= UCHAR
&&
125 p
->n_type
!= SHORT
&& p
->n_type
!= USHORT
)
127 p
->n_left
= block(SCONV
, p
->n_left
, NIL
, INT
, 0, MKAP(INT
));
137 * Remove unnecessary conversion ops.
139 if (clogop(l
->n_op
) && l
->n_left
->n_op
== SCONV
) {
140 if (coptype(l
->n_op
) != BITYPE
)
142 if (l
->n_right
->n_op
== ICON
) {
143 r
= l
->n_left
->n_left
;
144 if (r
->n_type
>= FLOAT
&& r
->n_type
<= LDOUBLE
)
146 /* Type must be correct */
151 l
->n_right
->n_type
= ty
;
154 else if (l
->n_right
->n_op
== SCONV
&&
155 l
->n_left
->n_type
== l
->n_right
->n_type
) {
156 r
= l
->n_left
->n_left
;
159 r
= l
->n_right
->n_left
;
168 /* Remove redundant PCONV's. Be careful */
170 if (l
->n_op
== ICON
) {
171 l
->n_lval
= (unsigned)l
->n_lval
;
174 if (l
->n_type
< INT
|| DEUNSIGN(l
->n_type
) == LONGLONG
) {
176 p
->n_left
= block(SCONV
, l
, NIL
,
177 UNSIGNED
, 0, MKAP(UNSIGNED
));
180 /* if left is SCONV, cannot remove */
181 if (l
->n_op
== SCONV
)
184 /* avoid ADDROF TEMP */
185 if (l
->n_op
== ADDROF
&& l
->n_left
->n_op
== TEMP
)
188 /* if conversion to another pointer type, just remove */
189 if (p
->n_type
> BTMASK
&& l
->n_type
> BTMASK
)
193 delp
: l
->n_type
= p
->n_type
;
194 l
->n_qual
= p
->n_qual
;
204 if (p
->n_type
== l
->n_type
) {
210 if ((p
->n_type
& TMASK
) == 0 && (l
->n_type
& TMASK
) == 0 &&
211 btattr
[p
->n_type
].atypsz
== btattr
[l
->n_type
].atypsz
) {
212 if (p
->n_type
!= FLOAT
&& p
->n_type
!= DOUBLE
&&
213 l
->n_type
!= FLOAT
&& l
->n_type
!= DOUBLE
&&
214 l
->n_type
!= LDOUBLE
&& p
->n_type
!= LDOUBLE
) {
215 if (l
->n_op
== NAME
|| l
->n_op
== UMUL
||
217 l
->n_type
= p
->n_type
;
225 if (DEUNSIGN(p
->n_type
) == INT
&& DEUNSIGN(l
->n_type
) == INT
&&
226 coptype(l
->n_op
) == BITYPE
) {
227 l
->n_type
= p
->n_type
;
232 if (DEUNSIGN(p
->n_type
) == SHORT
&&
233 DEUNSIGN(l
->n_type
) == SHORT
) {
238 /* convert float/double to int before to (u)char/(u)short */
239 if ((DEUNSIGN(p
->n_type
) == CHAR
||
240 DEUNSIGN(p
->n_type
) == SHORT
) &&
241 (l
->n_type
== FLOAT
|| l
->n_type
== DOUBLE
||
242 l
->n_type
== LDOUBLE
)) {
243 p
= block(SCONV
, p
, NIL
, p
->n_type
, p
->n_df
, p
->n_ap
);
244 p
->n_left
->n_type
= INT
;
248 /* convert (u)char/(u)short to int before float/double */
249 if ((p
->n_type
== FLOAT
|| p
->n_type
== DOUBLE
||
250 p
->n_type
== LDOUBLE
) && (DEUNSIGN(l
->n_type
) == CHAR
||
251 DEUNSIGN(l
->n_type
) == SHORT
)) {
252 p
= block(SCONV
, p
, NIL
, p
->n_type
, p
->n_df
, p
->n_ap
);
253 p
->n_left
->n_type
= INT
;
261 CONSZ val
= l
->n_lval
;
263 if (!ISPTR(m
)) /* Pointers don't need to be conv'd */
266 l
->n_lval
= l
->n_lval
!= 0;
269 l
->n_lval
= (char)val
;
272 l
->n_lval
= val
& 0377;
275 l
->n_lval
= (short)val
;
278 l
->n_lval
= val
& 0177777;
282 l
->n_lval
= val
& 0xffffffff;
286 l
->n_lval
= (int)val
;
289 l
->n_lval
= (long long)val
;
303 cerror("unknown type %d", m
);
308 } else if (o
== FCON
) {
309 l
->n_lval
= l
->n_dcon
;
321 if (o
== DIV
&& p
->n_type
!= CHAR
&& p
->n_type
!= SHORT
)
323 if (o
== MOD
&& p
->n_type
!= CHAR
&& p
->n_type
!= SHORT
)
325 /* make it an int division by inserting conversions */
326 p
->n_left
= block(SCONV
, p
->n_left
, NIL
, INT
, 0, MKAP(INT
));
327 p
->n_right
= block(SCONV
, p
->n_right
, NIL
, INT
, 0, MKAP(INT
));
328 p
= block(SCONV
, p
, NIL
, p
->n_type
, 0, MKAP(p
->n_type
));
329 p
->n_left
->n_type
= INT
;
334 if( p
->n_right
->n_op
!= ICON
) cerror( "bad conversion", 0);
336 p
= buildtree(o
==PMCONV
?MUL
:DIV
, p
->n_left
, p
->n_right
);
340 /* put return value in return reg */
342 p
->n_right
= p
->n_left
;
343 p
->n_left
= block(REG
, NIL
, NIL
, p
->n_type
, 0, MKAP(INT
));
344 p
->n_left
->n_rval
= RETREG(p
->n_type
);
350 printf("clocal out: %p\n", p
);
366 /* Write float constants to memory */
368 sp
= IALLOC(sizeof(struct symtab
));
370 sp
->sap
= MKAP(p
->n_type
);
371 sp
->slevel
= 1; /* fake numeric label */
372 sp
->soffset
= getlab();
374 sp
->stype
= p
->n_type
;
375 sp
->squal
= (CON
>> TSHIFT
);
378 ninval(0, sp
->sap
->atypsz
, p
);
390 return(1); /* all names can have & taken on them */
394 * at the end of the arguments of a ftn, set the automatic offset
403 * is an automatic variable of type t OK for a register variable
408 if (t
== INT
|| t
== UNSIGNED
|| t
== LONG
|| t
== ULONG
)
410 return 0; /* XXX - fix reg assignment in pftn.c */
414 * return a node, for structure references, which is suitable for
415 * being added to a pointer of type t, in order to be off bits offset
417 * t, d, and s are the type, dimension offset, and sizeoffset
418 * Be careful about only handling first-level pointers, the following
419 * indirections must be fullword.
422 offcon(OFFSZ off
, TWORD t
, union dimfun
*d
, struct attr
*sue
)
427 printf("offcon: OFFSZ %lld type %x dim %p siz %d\n",
430 p
= bcon(off
/SZCHAR
);
435 * Allocate off bits on the stack. p is a tree that when evaluated
436 * is the multiply count for off, t is a NAME node where to write
437 * the allocated address.
440 spalloc(NODE
*t
, NODE
*p
, OFFSZ off
)
443 int nbytes
= off
/ SZCHAR
;
445 p
= buildtree(MUL
, p
, bcon(nbytes
));
446 p
= buildtree(PLUS
, p
, bcon(7));
447 p
= buildtree(AND
, p
, bcon(~7));
449 /* subtract the size from sp */
450 sp
= block(REG
, NIL
, NIL
, p
->n_type
, 0, 0);
453 ecomp(buildtree(MINUSEQ
, sp
, p
));
455 /* save the address of sp */
456 sp
= block(REG
, NIL
, NIL
, PTR
+INT
, t
->n_df
, t
->n_ap
);
458 t
->n_type
= sp
->n_type
;
459 ecomp(buildtree(ASSIGN
, t
, sp
)); /* Emit! */
463 * print out a constant node
464 * mat be associated with a label
467 ninval(CONSZ off
, int fsz
, NODE
*p
)
469 union { float f
; double d
; int i
[2]; } u
;
478 t
= INT
; /* pointer */
480 if (p
->n_op
!= ICON
&& p
->n_op
!= FCON
)
481 cerror("ninval: init node not constant");
483 if (p
->n_op
== ICON
&& p
->n_sp
!= NULL
&& DEUNSIGN(t
) != INT
)
484 uerror("element not constant");
490 printf("\t.dword %lld\n", (long long)p
->n_lval
);
493 j
= p
->n_lval
& 0xffffffff;
499 ninval(off
+32, 32, p
);
504 ninval(off
+32, 32, p
);
510 p
->n_lval
= p
->n_lval
!= 0;
514 printf("\t.word " CONFMT
, (CONSZ
)p
->n_lval
);
515 if ((q
= p
->n_sp
) != NULL
) {
516 if ((q
->sclass
== STATIC
&& q
->slevel
> 0)) {
517 printf("+" LABFMT
, q
->soffset
);
520 q
->soname
? q
->soname
: exname(q
->sname
));
526 printf("\t.half %d\n", (int)p
->n_lval
& 0xffff);
530 printf("\t.byte %d\n", (int)p
->n_lval
& 0xff);
534 u
.d
= (double)p
->n_dcon
;
536 printf("\t.word\t%d\n", u
.i
[0]);
537 printf("\t.word\t%d\n", u
.i
[1]);
539 printf("\t.word\t%d\n", u
.i
[1]);
540 printf("\t.word\t%d\n", u
.i
[0]);
544 u
.f
= (float)p
->n_dcon
;
545 printf("\t.word\t0x%x\n", u
.i
[0]);
552 /* make a name look like an external name in the local machine */
562 * map types which are not defined on the local machine
567 switch (BTYPE(type
)) {
573 MODTYPE(type
,UNSIGNED
);
579 /* curid is a variable which is defined but
580 * is not initialized (and not a function );
581 * This routine returns the storage class for an uninitialized declaration
590 calldec(NODE
*p
, NODE
*q
)
595 extdec(struct symtab
*q
)
600 * Print out a string of characters.
601 * Assume that the assembler understands C-style escape
605 instring(struct symtab
*sp
)
612 /* be kind to assemblers and avoid long strings */
613 printf("\t.ascii \"");
614 for (s
= str
; *s
!= 0; ) {
619 fwrite(str
, 1, s
- str
, stdout
);
620 printf("\"\n\t.ascii \"");
624 fwrite(str
, 1, s
- str
, stdout
);
628 /* make a common declaration for id, if reasonable */
630 defzero(struct symtab
*sp
)
634 off
= tsize(sp
->stype
, sp
->sdf
, sp
->sap
);
635 off
= (off
+(SZCHAR
-1))/SZCHAR
;
636 printf(" .%scomm ", sp
->sclass
== STATIC
? "l" : "");
638 printf("%s,0%o\n", sp
->soname
? sp
->soname
: exname(sp
->sname
), off
);
640 printf(LABFMT
",0%o\n", sp
->soffset
, off
);
645 /* make a common declaration for id, if reasonable */
647 commdec(struct symtab
*q
)
651 off
= tsize(q
->stype
, q
->sdf
, q
->ssue
);
652 off
= (off
+(SZCHAR
-1))/SZCHAR
;
654 printf(" .comm %s,%d\n", exname(q
->soname
), off
);
657 /* make a local common declaration for id, if reasonable */
659 lcommdec(struct symtab
*q
)
663 off
= tsize(q
->stype
, q
->sdf
, q
->ssue
);
664 off
= (off
+(SZCHAR
-1))/SZCHAR
;
666 printf("\t.lcomm %s,%d\n", exname(q
->soname
), off
);
668 printf("\t.lcomm " LABFMT
",%d\n", q
->soffset
, off
);
672 * print a (non-prog) label.
677 printf(LABFMT
":\n", label
);
680 /* ro-text, rw-data, ro-data, ro-strings */
681 static char *loctbl
[] = { "text", "data", "rdata", "rdata" };
686 if (locc
== lastloc
&& locc
!= STRNG
)
688 if (locc
== RDATA
&& lastloc
== STRNG
)
691 if (locc
!= lastloc
) {
693 printf("\t.%s\n", loctbl
[locc
]);
697 printf("\t.align 2\n");
702 * Initialize a bitfield.
705 infld(CONSZ off
, int fsz
, CONSZ val
)
708 printf("infld off %lld, fsz %d, val %lld inbits %d\n",
709 off
, fsz
, val
, inbits
);
711 while (fsz
+ inbits
>= SZCHAR
) {
712 inval
|= (val
<< inbits
);
713 printf("\t.byte %d\n", inval
& 255);
714 fsz
-= (SZCHAR
- inbits
);
715 val
>>= (SZCHAR
- inbits
);
719 inval
|= (val
<< inbits
);
725 * set fsz bits in sequence to zero.
728 zbits(OFFSZ off
, int fsz
)
733 printf("zbits off %lld, fsz %d inbits %d\n", off
, fsz
, inbits
);
734 if ((m
= (inbits
% SZCHAR
))) {
741 printf("\t.byte %d\n", inval
);
746 printf("\t.zero %d\n", fsz
/SZCHAR
);
747 fsz
-= (fsz
/SZCHAR
) * SZCHAR
;
756 * va_start(ap, last) implementation.
758 * f is the NAME node for this builtin function.
759 * a is the argument list containing:
763 * It turns out that this is easy on MIPS. Just write the
764 * argument registers to the stack in va_arg_start() and
765 * use the traditional method of walking the stackframe.
768 mips_builtin_stdarg_start(NODE
*f
, NODE
*a
, TWORD t
)
773 /* check num args and type */
774 if (a
== NULL
|| a
->n_op
!= CM
|| a
->n_left
->n_op
== CM
||
775 !ISPTR(a
->n_left
->n_type
))
778 /* must first deal with argument size; use int size */
780 if (p
->n_type
< INT
) {
781 /* round up to word */
782 sz
= SZINT
/ tsize(p
->n_type
, p
->n_df
, p
->n_ap
);
785 p
= buildtree(ADDROF
, p
, NIL
); /* address of last arg */
786 p
= optim(buildtree(PLUS
, p
, bcon(sz
)));
787 q
= block(NAME
, NIL
, NIL
, PTR
+VOID
, 0, 0);
788 q
= buildtree(CAST
, q
, p
);
792 p
= buildtree(ASSIGN
, a
->n_left
, p
);
799 uerror("bad argument to __builtin_stdarg_start");
804 mips_builtin_va_arg(NODE
*f
, NODE
*a
, TWORD t
)
809 /* check num args and type */
810 if (a
== NULL
|| a
->n_op
!= CM
|| a
->n_left
->n_op
== CM
||
811 !ISPTR(a
->n_left
->n_type
) || a
->n_right
->n_op
!= TYPE
)
817 sz
= tsize(r
->n_type
, r
->n_df
, r
->n_ap
) / SZCHAR
;
818 if (sz
< SZINT
/SZCHAR
) {
819 werror("%s%s promoted to int when passed through ...",
820 r
->n_type
& 1 ? "unsigned " : "",
821 DEUNSIGN(r
->n_type
) == SHORT
? "short" : "char");
826 p
= tcopy(a
->n_left
);
827 if (sz
> SZINT
/SZCHAR
&& r
->n_type
!= UNIONTY
&& r
->n_type
!= STRTY
) {
828 p
= buildtree(PLUS
, p
, bcon(7));
829 p
= block(AND
, p
, bcon(-8), p
->n_type
, p
->n_df
, p
->n_ap
);
832 /* create a copy to a temp node */
833 q
= tempnode(0, p
->n_type
, p
->n_df
, p
->n_ap
);
835 p
= buildtree(ASSIGN
, q
, p
);
837 q
= tempnode(tmpnr
, p
->n_type
, p
->n_df
,p
->n_ap
);
838 q
= buildtree(PLUS
, q
, bcon(sz
));
839 q
= buildtree(ASSIGN
, a
->n_left
, q
);
841 q
= buildtree(COMOP
, p
, q
);
847 p
= tempnode(tmpnr
, INCREF(r
->n_type
), r
->n_df
, r
->n_ap
);
848 p
= buildtree(UMUL
, p
, NIL
);
849 p
= buildtree(COMOP
, q
, p
);
854 uerror("bad argument to __builtin_va_arg");
859 mips_builtin_va_end(NODE
*f
, NODE
*a
, TWORD t
)
867 mips_builtin_va_copy(NODE
*f
, NODE
*a
, TWORD t
)
869 if (a
== NULL
|| a
->n_op
!= CM
|| a
->n_left
->n_op
== CM
)
872 f
= buildtree(ASSIGN
, a
->n_left
, a
->n_right
);
877 uerror("bad argument to __buildtin_va_copy");
881 static int constructor
;
882 static int destructor
;
885 * Give target the opportunity of handling pragmas.
891 if (strcmp(str
, "tls") == 0) {
892 uerror("thread-local storage not supported for this target");
895 if (strcmp(str
, "constructor") == 0 || strcmp(str
, "init") == 0) {
899 if (strcmp(str
, "destructor") == 0 || strcmp(str
, "fini") == 0) {
908 * Called when a identifier has been declared, to give target last word.
911 fixdef(struct symtab
*sp
)
913 if ((constructor
|| destructor
) && (sp
->sclass
!= PARAM
)) {
914 printf("\t.section .%ctors,\"aw\",@progbits\n",
915 constructor
? 'c' : 'd');
916 printf("\t.p2align 2\n");
917 printf("\t.long %s\n", exname(sp
->sname
));
918 printf("\t.previous\n");
919 constructor
= destructor
= 0;
924 pass1_lastchance(struct interpass
*ip
)